javascript控件开发之滚动条控件

页面导航:首页 > 网络编程 > JavaScript > javascript控件开发之滚动条控件

javascript控件开发之滚动条控件

来源: 作者: 时间:2016-02-20 09:49 【

在网页中,本身就有滚动条,在显示文本内容的时候,原始的滚动条已够用,一般如果我们想实现一个类 20284;列表的控件时,也可以把所有的列表数据输出到一个完整的标签,再嵌入到
在网页中,
本身就有滚动条,在显示文本内容的时候,原始的滚动条已够用,一般如果我们想实现一个类似列表的控件时,也可以把所有的列表数据输出到一个完整的标签,再嵌入到一个DIV中即可,然而如果数据量达到几千行时,完全生成
的话,将会非常的占用内存,因此较好的办法是用虚拟展示的方式,
所谓虚拟展示就是把数据用一个数组存储, 然后只生成可见部分的DOM元素,比如可见行是10行,那就创建10个,通过刷新的方式,在这10行中,滚动显示所有的数据,这样,滚动条就是主要的一环节,
以上的说明等到我们做后面的列表展示控件时,大家就会明白,在此就不再详细说明,接下来我们进入主题,开发我们的滚动条控件。
本次我们做的滚动特性有,上、下两个按钮和拖动的按钮,其余特性遵照平时系统滚动条的规则来开发,其中滚动区域是通过设置明细数量来设置滚动数量,比如,总共有1000条数据,然后界面能显示50条,那滚动数量则是1000-50条,通过这个数据来绘制滚动条的滚动数量,这种方式实现滚动条是为后续虚拟滚动做准备
首先,基于行前几篇开发的的框架,我们在目录 component\ui\下添加文件 com.ui.scrollBar.js, 在文件中定义com.ui.scrollBar类,继承com.ui.window类,如下

/**
 * 滚动条控件.
 * 创建:QZZ
 * 日期:2014-03-01
 */
(function(undefined) {
	
	nameSpace("com.ui");
	/**
	 * 滚动条控件.
	 */
	com.ui.scrollBar = Extend(com.ui.window, {
	    /**
	     * 创建函数
	     */
	    create:function() {
	    },
	    /**
	     * 渲染.
	     */
	    render:function() {
	    }
	});
})();



在滚动条的创建函数中定义一些基本属性,如滚动条类型、滚动总数量、显示数量、滚动位置、滚动一条的步长及拖动按钮最短长度等,如下
		/**
		 * 创建函数
		 */
	create:function() {
	    	this.base();
            this.className = "com.ui.scrollBar";
            this.logInfo("create");
			//绑定明细总数量
			this.scrollCount = 0;
			//显示区域可见数量
			this.showCount = 0;
			//滚动位置
			this.scrollIndex = 0;
			//每步滚动像素长
			this.stepLen = 2;
			//拖动按钮最短长
			this.dragBoxMinLen = 20;
			//横、纵向滚动条
			this.option.scrollType = this.option.scrollType || "V";
			//滚动条是否可见
			this.visible = true;
			//按钮宽度
			this.btnWidth = 15;
			//初始化宽高属性
			if(this.option.scrollType == "V") {
			    this.option.width = this.option.width || 16;
			    this.option.height = this.option.height || 100;			
			} else if(this.option.scrollType == "H") {
			    this.option.width = this.option.width || 100;
			    this.option.height = this.option.height || 16;
			}
			this.dragState = false;
	},


定义好基本的属性后,开始绘制滚动条的框架, 这里我们采用
来实现, 比如纵向滚动条,则生成一个三行一列的
,第一行与第三行用作上下按钮,中间用作滚动区域,(横向的同理),
然后在滚动区域(上边
的第二行)中又加入一个两行一列的
,用作中间拖动按钮,第一行,绘制边线与背景相同,第二行绘制成按钮,通过调整第一行的行高来设定按钮的位置,
绘制完成后,添加按钮的事件,及拖动事件, 如下:

    /**
     * 渲染.
     */
    render:function() {
        this.base();
        //创建滚动条结构
if(this.scrollTable == null) { this.scrollTable = this.createElement("TABLE"); } //清除原有的行列,结构变化的时候,会有已存在行 while(this.scrollTable.rows.length > 0) { this.scrollTable.deleteRow(0); } //创建拖动按钮结构
if(this.dragTable == null) { this.dragTable = this.createElement("TABLE"); } //清除原有行列,结构变化的时候,会有已存在行, while(this.dragTable.rows.length > 0) { this.dragTable.deleteRow(0); } //插入行列 if(this.option.scrollType == "V" && this.scrollTable.rows.length != 3) { this.priorBtn = this.scrollTable.insertRow(0).insertCell(0); this.centerRect = this.scrollTable.insertRow(1).insertCell(0); this.nextBtn = this.scrollTable.insertRow(2).insertCell(0); this.dragLen = this.dragTable.insertRow(0).insertCell(0); this.dragBox = this.dragTable.insertRow(1).insertCell(0); this.centerRect.appendChild(this.dragTable); } else if(this.option.scrollType == "H" && this.scrollTable.rows.length != 1) { var tr = this.scrollTable.insertRow(0); this.priorBtn = tr.insertCell(0); this.centerRect = tr.insertCell(1); this.nextBtn = tr.insertCell(2); var tr1 = this.dragTable.insertRow(0); this.dragLen = tr1.insertCell(0); this.dragBox = tr1.insertCell(1); this.centerRect.appendChild(this.dragTable); } var _this = this; //拖动框鼠标按下事件, 并打印标志dragState,把控件置为焦点 this.dragBox.onmousedown = function(ev) { //拖动状态 _this.dragState = true; _this.focus = true; } //上一个按钮鼠标按下事件,这里处理长按时的效果,采用延迟执行的方式, //scrollPrior()函数,是后续定义的向上滚动一行的函数, this.setInt = null; this.priorBtn.onmousedown = function(ev) { _this.scrollPrior(); _this.mouseDown = true; setTimeout(function() { if(_this.mouseDown) { _this.setInt = setInterval(function() { _this.scrollPrior(); if(_this.scrollIndex == _this.scrollCount - _this.showCount) { clearInterval(_this.setInt); } }, 50);//setInterval } }, 500); //setTimeout } //下一个按钮鼠标按下事件,这里处理长按时的效果,采用延迟执行的方式, //scrollNext()函数,是后续定义的向下滚动一行的函数, this.nextBtn.onmousedown = function(ev) { _this.scrollNext(); _this.mouseDown = true; setTimeout(function() { if(_this.mouseDown) { _this.setInt = setInterval(function() { _this.scrollNext(); if(_this.scrollIndex == _this.scrollCount - _this.showCount) { clearInterval(_this.setInt); }; }, 50); //setInterval } }, 500); //setTimeout } //中间区域鼠标按下事件, 控制向下、上翻页, //scrollPriorPage, scrollNextPage是后继定义的翻页函数。 this.centerRect.onmousedown = function(ev) { var ev = ev || event; if(_this.dragState != true) { var dlen = 0, clen; //debugger; var rect = this.getBoundingClientRect(); if(_this.option.scrollType == "V") { dlen = _this.dragLen.offsetHeight; clen = ev.clientY - rect.top; } else if(_this.option.scrollType == "H") { dlen = _this.dragLen.offsetWidth; clen = ev.clientX - rect.left; } if(clen > dlen) { _this.scrollPriorPage(); } else { _this.scrollNextPage(); } } } //添加到win容器中 this.win.appendChild(this.scrollTable); //刷新滚动条框, 该方法为后继定义的函数,用于刷新滚动的样式及位置。 this.refreshBox(); },


上边我们只是绘制出滚动条的结构,需要进行样式控制,下边refreshBox函数就是用于控制滚动条的样式及位置的,
    /**
     * 刷新布局
     */
    refreshBox:function() {
        var rw = this._getRectWidth(), rh = this._getRectHeight()
        //设置按钮的样式及长、宽度,
        if(this.option.scrollType == "V") {
            this.priorBtn.style.height = this.btnWidth - 1 + "px";
            this.setStyle(this.priorBtn, "scrollUp");
            this.centerRect.style.height = (rh - 2 * this.btnWidth) + "px";
            this.setStyle(this.centerRect, "scrollCell");
            this.nextBtn.style.height = this.btnWidth - 1 + "px";
            this.setStyle(this.nextBtn, "scrollDown");
            this.dragTable.style.width = (rw - 1) + "px";
            this.dragLen.style.height = "0px";
            this.dragBox.style.height = this.btnWidth + "px";
        } else if(this.option.scrollType == "H") {
            this.priorBtn.style.width = this.btnWidth + "px";
            this.setStyle(this.priorBtn, "scrollPrior");
            this.centerRect.style.width = (rw - 2 * this.btnWidth) + "px";
            this.setStyle(this.centerRect, "scrollCell");
            this.nextBtn.style.width = this.btnWidth + "px";
            this.setStyle(this.nextBtn, "scrollNext");
            this.dragTable.style.height = rh + "px";
            this.dragLen.style.width = "0px";				
            this.dragBox.style.width = this.btnWidth + "px";				
        }
        //设置滚动区域的样式,及拖动按钮的样式,
        this.setStyle(this.dragLen, "scrollCell");
        this.setStyle(this.dragBox, "scrollDrag");
        //设置滚动表格和拖动表格的样式,
        this.setStyle(this.scrollTable, "scrollBox");
        this.setStyle(this.dragTable, "scrollBox");
        //设置宽、高
        this.scrollTable.style.width = rw + "px";
        this.scrollTable.style.height = rh + "px";
    },


这上边用到几个样式,在com.comStyle.css文件中定义如下:
.scrollBox {
    border-collapse:collapse;
    border-spacing:0px;
	padding:0px;
}


.scrollCell {
    padding:0px;
	vertical-align:top;
	background-color:#eeeeee;
}


.scrollUp {
    padding:0px;
	background-color:#ddeeff;
	border-Bottom:1px solid #C3D2E6;
}


.scrollDown {
    padding:0px;
	background-color:#ddeeff;
	border-Top:1px solid #C3D2E6;
}


.scrollPrior {
    padding:0px;
	background-color:#ddeeff;
	border-right:1px solid #C3D2E6;
}


.scrollNext {
    padding:0px;
	background-color:#ddeeff;
	border-Left:1px solid #C3D2E6;
}


.scrollDrag {
    padding:0px;
	background-color:#ddeeff;
	border:1px solid #C3D2E6;
}


完成以上结构后,只是完成了显示的效果,因为我们这个滚动条是通过设置数据明细数量来设定滚动的,因此需要与象素进行转换计算,以设置拖动按钮的位置,下面我们添加一个刷新函数,用于刷新滚动条的长度、拖动按钮的长度及位置,添加refresh函数,如下:
    /**
     *跟据滚动数据,刷新滚动条位置
     */
    refresh:function() {
        //计算滚动区域外的数量
        var sl = this.scrollCount - this.showCount;
        //发生了变化才重新计算
        if(sl != this.tmpCount) {
            //计算总象素长度
            var slpx = sl * this.stepLen;
            //计算拖动框长度
            var cenLen = this.option.scrollType == "V"?
                this.centerRect.offsetHeight:this.centerRect.offsetWidth;
            var dragBoxLen = cenLen - slpx;
            //如果计算出来的拖动按钮过短,则重新计算步长,保证按钮不再缩短
            if(dragBoxLen < this.dragBoxMinLen) {
                dragBoxLen = this.dragBoxMinLen;
                slpx = cenLen - dragBoxLen;
                this.stepLen = slpx/(this.scrollCount - this.showCount);
            } else {
                this.stepLen = 2;
            }
            //设置拖动按钮长度
            if(this.option.scrollType == "V") {
                this.dragBox.style.height = (dragBoxLen - 2) + "px";
            } else if(this.option.scrollType == "H") {
                this.dragBox.style.width = (dragBoxLen - 2) + "px";
            }
            //缓存当前数量
            this.tmpCount = sl;
        }
        //计算拖动框位置
        var len = parseInt(this.scrollIndex * this.stepLen, 10);
        if(len < 0) {
            len = 0;
        } else if(len > cenLen - dragBoxLen) {
            len = cenLen - dragBoxLen
        }
        //设置位置值
        if(this.option.scrollType == "V") {
            this.dragLen.style.height = len + "px";
        } else if(this.option.scrollType == "H") {
            this.dragLen.style.width = len + "px";
        }
    },


下面我们实现 拖动的事件,首先要先在鼠标按钮的时候初始化一些属性,再在鼠标弹起的时候,还原一些属性,这里我能通过重写doMouseDown,doMouseUp事件来实现,如下:
    /**
     *鼠标按下事件
     */
    doMouseDown:function(ev) {
        this.base(ev);
        //记录原鼠标的按下位置
        this.dragX = ev.clientX;
        this.dragY = ev.clientY;
        //记录原按钮的位置,
        if(this.option.scrollType == "V") {
            this.dragPosition = this.dragLen.offsetHeight;
        } else if(this.option.scrollType == "H") {
            this.dragPosition = this.dragLen.offsetWidth;
        }
        //标识按钮状态
        this.mouseDown = true;
    },
    /**
     *鼠标弹起事件
     */
    doMouseUp:function(ev) {
        this.base(ev);
        //还原拖动状态
        this.dragState = false;
        //取消长按效果
        if(this.setInt != null) {
            clearInterval(this.setInt);
            this.setInt = null;
        }
        //标识按钮状态
        this.mouseDown = false;
    },


下面为鼠标移动事件,当拖动状态dragState等于true时,跟据鼠标的起始位置及当前位置计算滚动按钮的移动距离,并计算相应的滚动明细位置scrollIndex,并且执行滚动事件onScroll绑定的事件,由于滚动事件属于外部事件,这里作异常捕获处理。
        /**
         *鼠标移动事件
         */
        doMouseMove:function(ev) {
            if(this.dragState) {
                var len = 0, dragBoxLen = 0, centerLen = 0;
                //计算设置拖动按钮的位置,
                if(this.option.scrollType == "V") {
                    dragBoxLen = this._domValue(this.dragBox.style.height);
                    centerLen = this._domValue(this.centerRect.style.height);
                    len = this.dragPosition + ev.clientY - this.dragY;
                    if(len < 0) {
                        len = 0;
                    } else if(len > centerLen - dragBoxLen) {
                        len = centerLen - dragBoxLen;
                    }
                    this.dragLen.style.height = len + "px";
                } else if(this.option.scrollType == "H") {
                    dragBoxLen = this._domValue(this.dragBox.style.width);
                    centerLen = this._domValue(this.centerRect.style.width);
                    len = this.dragPosition + ev.clientX - this.dragX;
                    if(len < 0) {
                        len = 0;
                    } else if(len > centerLen - dragBoxLen) {
                        len = centerLen - dragBoxLen - 2;
                    }
                    this.dragLen.style.width = len + "px";
                }
                //计算明细数量位置
                var tmpScrollIndex = this.scrollIndex;
                if(dragBoxLen < 1) {
                    this.scrollIndex = 0;
                } else if(len >= centerLen - dragBoxLen) {
                    this.scrollIndex = this.scrollCount - this.showCount;
                } else {
                    this.scrollIndex = parseInt(len/this.stepLen, 10);
                }
                //执行滚动事件
                if(typeof this.onScroll == "function") {
                    try {
                        this.onScroll(this.scrollIndex, this.scrollIndex - tmpScrollIndex);
                    } catch(e) {
                        this.logInfo("onScroll Error!" + e.message);
                    }
                }
            }
        },


下面我们再定义上边用到的上、下明细函数,及上、下翻页函数,如下:
        /**
         * 向上滚动
         */
        scrollPrior:function() {
            if(this.scrollIndex > 0) {
                this.scrollIndex --;
                if(typeof this.onScroll == "function") {
                    this.onScroll(this.scrollIndex, -1);


                }
                this.refresh();
            }
        }, 
        /**
         * 向下滚动
         */
        scrollNext:function() {
            if(this.scrollIndex < this.scrollCount - this.showCount) {
                this.scrollIndex ++;
                if(typeof this.onScroll == "function") {
                    try {
                        this.onScroll(this.scrollIndex, 1);
                    } catch(e) {
                        this.logInfo("onScroll Error!" + e.message);
                    }
                }
                this.refresh();
            }
        },
        /**
         * 向上滚动翻页
         */
        scrollPriorPage:function() {
            var tmpIndex = this.scrollIndex;
            this.scrollIndex += this.showCount;
            if(this.scrollIndex > this.scrollCount - this.showCount) {
                this.scrollIndex = this.scrollCount - this.showCount;
            }
            if(tmpIndex != this.scrollIndex) {
                if(typeof this.onScroll == "function") {
                    try {
                        this.onScroll(this.scrollIndex, this.scrollIndex - tmpIndex);
                    } catch(e) {
                        this.logInfo("onScroll Error!" + e.message);
                    }
                }
                this.refresh();
            }
        },
        /**
         * 向下滚动翻页
         */
        scrollNextPage:function() {
            var tmpIndex = this.scrollIndex;
            this.scrollIndex -= this.showCount;
            if(this.scrollIndex < 0) {
                this.scrollIndex = 0;
            }
            if(tmpIndex != this.scrollIndex) {
                if(typeof this.onScroll == "function") {
                    try {
                        this.onScroll(this.scrollIndex, this.scrollIndex - tmpIndex);
                    } catch(e) {
                        this.logInfo("onScroll Error!" + e.message);
                    }
                }
                this.refresh();
            }        
        },


接着,再定义几个属性的设置函数,如下:
        /**
         *滚动条总数量
         */
        setScrollCount:function(value) {
            this.scrollCount = value;
        },
        /**
         *滚动条显示数量
         */
        setShowCount:function(value) {
            if(value >= this.scrollCount) {
                this.showCount = this.scrollCount;
                this.dragTable.style.display = "none";
            } else {
                this.showCount = value;
                this.dragTable.style.display = "";
            }
        },
        /**
         *滚动条滚到第几个位置
         */
        setScrollIndex:function(index) {
            if(index < 0) {
                index = 0;
            } else if(index > this.scrollCount - this.showCount) {
                index = this.scrollCount - this.showCount;
            }
            if(this.scrollIndex != index) {
                var tmpIndex = this.scrollIndex;
                this.scrollIndex = index;
                if(typeof this.onScroll == "function") {
                    try {
                        this.onScroll(this.scrollIndex, this.scrollIndex - tmpIndex);
                    } catch(e) {
                        this.logInfo("onScroll Error!" + e.message);
                    }
                }
            }            
        },


最后设置高度,宽度的函数,
		/**
		 * 设置高度.
		 */
		setHeight:function(height) {
		    this.base(height);
			this.refreshBox();
			this.refresh();
		},
		/**
		 * 设置宽度.
		 */
		setWidth:function(width) {
		    this.base(width);
			this.refreshBox();
			this.refresh();
		}	


到此我们的全部控件编写完成,从上边来看,有点长,但是这点长绝对值得,因为后续控件,将会大大降低实现难度,这里有个缺点,就是没有给向上、下按钮添加图片,不过,如果需要只需要修改样式文件,把图片加上即可,
当然,我们写了控制,那么就要测试一下,下面我们写几行代码,用来测试控件的使用,
首先在test.html文件中添加两个滚动条控件的标签,如下id=test12/13的两个控件:

  test
    <script src="../script/common/init.js" type="text/javascript"></script>
    
      
    
确定
取消
退出


然后我们在页面控制器中添加一些代码,
/**
 * test.html页面控制类
 * 创建:qzz
 * 日期: 2014-05-01
 */
(function(undefined) {
    /**
     * 控制类
     */     
    testControllor = Extend(pageControllor, {
        //初始化页面
        initPage:function() {
            //修改页面上的控件属性,绑定事件
            this.test2.onClick = function() {
                alert("确定");
            }
            this.test2.setCaption("确定");
            this.test2.setWidth(50);
            this.test3.onClick = function() {
                alert("取消");
            }
            this.test3.setCaption("取消");
            this.test11.onClick = function() {
                alert("退出");
            }
            this.test12.setScrollCount(50);
            this.test12.setShowCount(10);
            this.test12.setScrollIndex(17);
            this.test12.refresh();
            
            this.test13.setScrollCount(100);
            this.test13.setShowCount(10);
            this.test13.setScrollIndex(17);
            this.test13.setWidth(400);
            //this.test13.refresh();
        }
    });
})();
/**
 * 页面对象创建,且启动
 */
thisWindow.onShow = function() {
    var tc = new testControllor();
    tc.initPage();
}


如此就可以打开test.html页面查看效果,如图
n峨n丁下载包查看
请关注我的下一编,javascript控件开发之列表控件(1)
Tags:

文章评论


<