(function (win, dom) { /** * 参数: * o [object] * o.selid -> 滚动内容盒子的id (必须) * o.width -> 滚动条的宽度 (默认10,请设置为偶数) * o.bgcolor -> 滚动条包裹层的颜色 (默认#eaeaea) * o.barcolor -> 滚动条的颜色 (默认#ccc) * o.entershow -> 是否为鼠标进入包裹层后显示滚动条 (默认true是) * o.hasy -> 是否需要y轴滚动条(默认true需要) * o.hasx -> 是否需要x轴滚动条(默认false不需要) * o.borderradius -> 滚公条圆弧的宽度(默认为o.width的一半) * 注:通过调用myscrollbar.setsize()函数可以重置滚动条高度 */ function myscrollbar (o) { this.init(o); } myscrollbar.prototype.init = function (o) { this.bxbar = false; // 是否有x轴滚动条 this.bybar = false; // 是否有y轴滚动条 this.iscrolltop = 0; // 滚动内容的y轴滚动距离 this.iscrollleft = 0; // 滚动内容的x轴滚动距离 this.byshow = false; // y轴滚动条显示与否 this.bxshow = false; // x轴滚动条显示与否 this.owrapper = dom.getelementbyid(o.selid); // 滚动盒子 this.oscroll = this.owrapper.firstelementchild; // 滚动内容 this.setparam(o); // 调用设置初始参数喊 this.addscrollbar(); // 调用添加滚动条函数 this.initstate(); // 调用设置初始状态函数 this.initevent(); // 调用设置事件函数 } // 初始化状态 myscrollbar.prototype.initstate = function () { // 给包裹层设置默认定位 var swposition = getstyle(this.owrapper, 'position'); if(swposition == 'static') { setstyle(this.owrapper, { position: 'relative' }) } setstyle(this.oscroll, { position: 'relative' }) if ( this.bybar ) { setstyle(this.oybox, { display: this.entershow ? 'none' : 'block', // 如果entershow为true就是需要进入包裹层才显示滚动条 position: 'absolute', top: 0, right: 0, zindex: 10, width: this.width + 'px', height: '100%', "border-radius":" 30px", backgroundcolor: this.bgcolor }); setstyle(this.oybar, { position: 'absolute', top: 0, left: 0, width: '100%', backgroundcolor: this.barcolor, borderradius: this.borderradius + 'px' }) } if ( this.bxbar ) { setstyle(this.oxbox, { display: this.entershow ? 'none' : 'block', // 如果entershow为true就是需要进入包裹层才显示滚动条 position: 'absolute', bottom: 0, left: 0, zindex: 10, height: this.width + 'px', width: '100%', backgroundcolor: this.bgcolor }) setstyle(this.oxbar, { position: 'absolute', bottom: 0, left: 0, height: '100%', backgroundcolor: this.barcolor, borderradius: this.borderradius + 'px' }) } this.setsize(); // 设置滚动条的宽高 } // 初始化事件 myscrollbar.prototype.initevent = function () { var _this = this; // 鼠标在包裹层中然后滚轴上下滚动 var suseragent = win.navigator.useragent.tolowercase(); if ( suseragent.indexof('firefox') != -1 ) { // 火狐浏览器滚轴滚动 this.owrapper.addeventlistener('dommousescroll', function (e) { if ( _this.bybar && _this.byshow ) { e.preventdefault(); _this.iscrolltop += e.detail > 0 ? 60 : -60; _this.iscrolltop = _this.iscrolltop <= 0 ? 0 : _this.iscrolltop >= _this.iscrollh - _this.iwrapperh ? _this.iscrollh - _this.iwrapperh : _this.iscrolltop; _this.settranslate(); _this.setytop(_this.iscrolltop / _this.iscrollh * _this.iyboxh); } }) } else { // 谷歌、ie滚轴滚动 this.owrapper.onmousewheel = function (evt) { if ( _this.bybar && _this.byshow ) { var e = evt || win.event; evt ? e.preventdefault() : e.returnvalue = false; _this.iscrolltop += e.wheeldelta < 0 ? 60 : -60; _this.iscrolltop = _this.iscrolltop <= 0 ? 0 : _this.iscrolltop >= _this.iscrollh - _this.iwrapperh ? _this.iscrollh - _this.iwrapperh : _this.iscrolltop; _this.settranslate(); _this.setytop(_this.iscrolltop / _this.iscrollh * _this.iyboxh); } } } // 输入表移入包裹层显示滚动条、移出隐藏滚动条 var isinwrapper = false; this.owrapper.onmouseenter = function () { isinwrapper = true; if ( _this.entershow ) { if ( _this.bybar && _this.byshow ) { setstyle(_this.oybox, { display: 'block' }) } if ( _this.bxbar && _this.bxshow ) { setstyle(_this.oxbox, { display: 'block' }) } } } this.owrapper.onmouseleave = function () { isinwrapper = false; if ( _this.entershow ) { if ( _this.bybar && !bydown && _this.byshow ) { setstyle(_this.oybox, { display: 'none' }) } if ( _this.bxbar && !bxdown && _this.bxshow ) { setstyle(_this.oxbox, { display: 'none' }) } } } // 鼠标在滚动条上按下,想要拖动 var bydown = false, bxdown = false; // 在滚动条上是否按下 var byleave = true, bxleave = true; // 是否离开 var idownpagey = 0, idownpagex = 0; // 按下时鼠标到页面顶部的距离 var iybartop = 0, ixbarleft = 0; // 按下时滚动条的top/left if ( this.bybar ) { // 鼠标移上y轴滚动条变色 if ( this.entercolor ) { this.oybar.onmouseenter = function () { byleave = false; setstyle(this, { backgroundcolor: _this.entercolor }) } this.oybar.onmouseleave = function () { byleave = true; if ( !bydown ) { setstyle(this, { backgroundcolor: _this.barcolor }) } } } // 鼠标在y轴滚动条按下 this.oybar.onmousedown = function (e) { if ( _this.byshow ) { bydown = true; idownpagey = e.clienty + dom.documentelement.scrolltop || dom.body.scrolltop; iybartop = parseint(getstyle(this, 'top')); // 禁止文本可选中 canselecttext(false); } } // 鼠标在按下y轴滚动条后抬起 dom.addeventlistener('mouseup', function () { if ( bydown && _this.byshow ) { bydown = false; // 恢复文本可选中 canselecttext(true); if ( !isinwrapper && _this.entershow ) { setstyle(_this.oybox, { display: 'none' }) } } if ( !bydown && byleave ) { setstyle(_this.oybar, { backgroundcolor: _this.barcolor }) } }) // 鼠标按下y轴滚动条后拖动 dom.addeventlistener('mousemove', function (e) { if ( bydown && _this.byshow ) { var inowpagey = e.clienty + dom.documentelement.scrolltop || dom.body.scrolltop; var inowtop = iybartop + inowpagey - idownpagey; inowtop = inowtop <= 0 ? 0 : inowtop >= _this.iyboxh - _this.iybarh ? _this.iyboxh - _this.iybarh : inowtop; _this.iscrolltop = inowtop / _this.iyboxh * _this.iscrollh; _this.settranslate(); _this.setytop(inowtop); } }) // 禁止默认拖动事件 this.oybar.ondrag = function (e) { var e = evt || win.event; evt ? e.preventdefault() : e.returnvalue = false; } } if ( this.bxbar ) { // 鼠标移上y轴滚动条变色 if ( this.entercolor ) { this.oxbar.onmouseenter = function () { bxleave = false; setstyle(this, { backgroundcolor: _this.entercolor }) } this.oxbar.onmouseleave = function () { bxleave = true; if ( !bxdown ) { setstyle(this, { backgroundcolor: _this.barcolor }) } } } // 鼠标在x轴滚动条按下 this.oxbar.onmousedown = function (e) { if ( _this.bxshow ) { bxdown = true; idownpagex = e.clientx + dom.documentelement.scrollleft || dom.body.scrollleft; ixbarleft = parseint(getstyle(this, 'left')); // 禁止文本可选中 canselecttext(false); } } // 鼠标在按下x轴滚动条后抬起 dom.addeventlistener('mouseup', function () { if ( bxdown && _this.bxshow ) { bxdown = false; // 恢复文本可选中 canselecttext(true); if ( !isinwrapper && _this.entershow ) { setstyle(_this.oxbox, { display: 'none' }) } } if ( !bxdown && bxleave ) { setstyle(_this.oxbar, { backgroundcolor: _this.barcolor }) } }) // 鼠标按下x轴滚动条后拖动 dom.addeventlistener('mousemove', function (e) { if ( bxdown && _this.bxshow ) { var inowpagex = e.clientx + dom.documentelement.scrollleft || dom.body.scrollleft; var inowleft = ixbarleft + inowpagex - idownpagex; inowleft = inowleft <= 0 ? 0 : inowleft >= _this.ixboxw - _this.ixbarw ? _this.ixboxw - _this.ixbarw : inowleft; _this.iscrollleft = inowleft / _this.ixboxw * _this.iscrollw; _this.settranslate(); _this.setxleft(inowleft); } }) // 禁止默认拖动事件 this.oxbar.ondrag = function (e) { var e = evt || win.event; evt ? e.preventdefault() : e.returnvalue = false; } } } // 设置默认参数 myscrollbar.prototype.setparam = function (o) { this.width = o.width ? o.width : 10; // 滚动条的宽度 this.bgcolor = o.bgcolor ? o.bgcolor : '#eaeaea'; // 滚动条背景颜色 this.barcolor = o.barcolor ? o.barcolor : '#ccc'; // 滚动条颜色 this.entercolor = o.entercolor || false; // 鼠标移上滚动条时的颜色 this.entershow = o.entershow === false ? false : true; // 是否进入包裹层在显示滚动条 this.hasy = o.hasy === false ? false : true; // 是否有y轴滚动条 this.hasx = o.hasx === true ? true : false; // 是否有x轴滚动条 this.borderradius = o.borderradius >= 0 ? o.borderradius : this.width / 2; // 圆角 } // 判断是否添加xy轴滚动条 myscrollbar.prototype.addscrollbar = function () { // 获取包裹层与滚动层的尺寸 this.getsize(); if ( this.iwrapperw <= this.iscrollw && this.hasx ) { this.bxbar = true; this.oxbox = dom.createelement('div'); // x轴滚动条盒子 this.oxbar = dom.createelement('div'); // x轴滚动条 this.oxbox.appendchild(this.oxbar); // 滚动条插入滚动条盒子 this.owrapper.insertbefore(this.oxbox, this.oscroll); // 滚动条盒子插到oscroll之前 } if ( this.iwrapperh <= this.iscrollh && this.hasy ) { this.bybar = true; this.oybox = dom.createelement('div'); // x轴滚动条盒子 this.oybar = dom.createelement('div'); // x轴滚动条 this.oybox.appendchild(this.oybar); // 滚动条插入滚动条盒子 this.owrapper.insertbefore(this.oybox, this.oscroll); // 滚动条盒子插到oscroll之前 } } // 更新/获取包裹层与滚动层的尺寸 myscrollbar.prototype.getsize = function () { var owrappersize = getclientsize(this.owrapper); var oscrollsize = getclientsize(this.oscroll); this.iwrapperclientw = owrappersize.width; this.iwrapperclienth = owrappersize.height; this.ipaddingt = parseint(getstyle(this.owrapper, 'paddingtop')); this.ipaddingr = parseint(getstyle(this.owrapper, 'paddingright')); this.ipaddingb = parseint(getstyle(this.owrapper, 'paddingbottom')); this.ipaddingl = parseint(getstyle(this.owrapper, 'paddingleft')); this.iwrapperw = owrappersize.width - this.ipaddingr - this.ipaddingl; this.iwrapperh = owrappersize.height - this.ipaddingt - this.ipaddingb; this.iscrollw = oscrollsize.width; this.iscrollh = oscrollsize.height; if ( this.bybar ) { this.iyboxh = owrappersize.height; this.iybarh = this.iwrapperh / this.iscrollh * this.iyboxh; } if ( this.bxbar ) { this.ixboxw = owrappersize.width; this.ixbarw = this.iwrapperw /this.iscrollw * this.ixboxw; } } // 设置尺寸 myscrollbar.prototype.setsize = function () { // 更新包裹层与滚动层的尺寸 this.getsize(); if ( this.bybar ) { if ( this.iwrapperh >= this.iscrollh ) { setstyle(this.oybox, { display: 'none' }) this.byshow = false; } else { if ( !this.entershow ) { setstyle(this.oybox, { display: 'block' }) } setstyle(this.oybar, { height: this.iybarh + 'px', top: 0 }) this.byshow = true; } } if ( this.bxbar ) { if ( this.iwrapperw >= this.iscrollw ) { setstyle(this.oxbox, { display: 'none' }) this.bxshow = false; } else { if ( !this.entershow ) { setstyle(this.oxbox, { display: 'block' }) } setstyle(this.oxbar, { width: this.ixbarw + 'px', left: 0 }) this.bxshow = true; } } this.iscrolltop = 0; this.iscrollleft = 0; this.settranslate(); } /** * 作用:设置oscroll的位置转换transform:translate * itime -> 动画时间,大于0有效,否则无动画,毫秒 */ myscrollbar.prototype.settranslate = function (itime) { var stranslate = 'translate(-' + this.iscrollleft + 'px, -' + this.iscrolltop + 'px)'; setstyle(this.oscroll, { transition: itime >= 0 ? itime + 'ms ease-in-out' : 0 + 'ms', transform: stranslate, mstransform: stranslate, moztransform: stranslate, webkittransform: stranslate, otransform: stranslate }) } // 设置滚动top myscrollbar.prototype.setytop = function (itop, itime) { setstyle(this.oybar, { transition: itime >= 0 ? itime + 'ms ease-in-out' : 0 + 'ms', top: itop + 'px' }) } // 设置滚动left myscrollbar.prototype.setxleft = function (ileft, itime) { setstyle(this.oxbar, { transition: itime >= 0 ? itime + 'ms ease-in-out' : 0 + 'ms', left: ileft + 'px' }) } /** * 作用:跳到指定位置 * o.id -> 要跳到那个id的位置; * o.pos -> 要跳到那个具体的位置,如果为字符串(两个选中择'top','bottom','left','right'), 如果为对象({top: number, left: number}),为对象时如果要y轴滚动条滚动就设置top,要两个轴一起滚动才一起设置。 * o.time -> 动画时间,不设没有动画 * 注:如果id存在,则pos不生效 */ myscrollbar.prototype.jump = function (o) { var opos = {top: 0, left: 0}; var itop = 0; var ibottome = this.iscrollh - this.iwrapperclienth + this.ipaddingt + this.ipaddingb > 0 ? this.iscrollh - this.iwrapperclienth + this.ipaddingt + this.ipaddingb : 0; var ileft = 0; var iright = this.iscrollw - this.iwrapperclientw + this.ipaddingl + this.ipaddingr > 0 ? this.iscrollw - this.iwrapperclientw + this.ipaddingl + this.ipaddingr : 0; if ( o.id ) { var obj = document.getelementbyid(o.id); opos = getposition(obj, this.oscroll); if ( this.bybar ) { opos.top += this.ipaddingt; } if ( this.bxbar ) { opos.left += this.ipaddingl; } } else if ( o.pos ) { if ( typeof o.pos == 'string' ) { switch(o.pos) { case 'top': opos.top = itop; break; case 'bottom': opos.top = ibottome; break; case 'left': opos.left = ileft; break; case 'right': opos.left = iright; break; default: break; } } else if ( typeof o.pos == 'object' ) { opos = o.pos; } } opos.top = opos.top > ibottome ? ibottome : opos.top >= 0 ? opos.top : 0; opos.left = opos.left > iright ? iright : opos.left >= 0 ? opos.left : 0; this.iscrolltop = opos.top; this.iscrollleft = opos.left; this.settranslate(o.time || 0); if ( this.bybar ) { this.setytop(this.iscrolltop / this.iscrollh * this.iyboxh, o.time || 0); } if ( this.bxbar ) { this.setxleft(this.iscrollleft / this.iscrollw * this.ixboxw, o.time || 0); } } // 获取样式 function getstyle (obj, name) { if(win.getcomputedstyle) { return getcomputedstyle(obj, null)[name]; } else { return obj.currentstyle[name]; } } // 设置样式 function setstyle (obj, ostyle) { for(var i in ostyle) { obj.style[i] = ostyle[i]; } } /** * 作用:获取对象的offset(内容尺寸+padding+border)尺寸,display:none;元素也可以获取 * 参数:obj -> 要获取尺寸的元素 * 返回:res -> width 宽; res -> height 高 * 依赖:getstyle,setstyle */ function getoffsetsize (obj) { var sdisplay = getstyle(obj, "display"); var res = {} if ( sdisplay != "none" ) { res.width = obj.offsetwidth; res.height = obj.offsetheight; } else { var oldstyle = { position: getstyle(obj, "position"), visibility: getstyle(obj, "visibility"), display: sdisplay } var newstyle = { position: "absolute", visibility: "hidden", display: "inline-block" } setstyle(obj, newstyle); res.width = obj.offsetwidth; res.height = obj.offsetheight; setstyle(obj, oldstyle); } return res; } // 计算实际内容+padding宽高即clientwidth/clientheight,但ie时client包含边框 function getclientsize (obj) { var itopw = parseint(getstyle(obj, 'bordertopwidth')); var irightw = parseint(getstyle(obj, 'borderrightwidth')); var ibottomw = parseint(getstyle(obj, 'borderbottomwidth')); var ileftw = parseint(getstyle(obj, 'borderleftwidth')); var ooffset = getoffsetsize(obj); return { width: ooffset.width <= 0 ? ooffset.width : ooffset.width - ileftw - irightw, height: ooffset.height <= 0 ? ooffset.height : ooffset.height - itopw - ibottomw } } // 禁止与恢复文本可选中,true为可选中,false为不可选中 function canselecttext (bcan) { if ( !bcan ) { dom.body.style.mozuserselect = 'none'; dom.body.style.webkituserselect = 'none'; dom.body.style.msuserselect = 'none'; dom.body.style.khtmluserselect = 'none'; dom.body.style.userselect = 'none'; } else { dom.body.style.mozuserselect = 'text'; dom.body.style.webkituserselect = 'text'; dom.body.style.msuserselect = 'text'; dom.body.style.khtmluserselect = 'text'; dom.body.style.userselect = 'text'; } } /** * 作用:获取obj到目标goal的position距离 */ function getposition (obj, goal) { var opos = { top: obj.offsettop, left: obj.offsetleft } if ( obj.parentnode != goal ) { var obj = getposition(obj.parentnode, goal); opos.top += obj.top; opos.left += obj.left; } else { return opos; } } if ( typeof define === "function" && define.amd ) { define([], function () { return myscrollbar; }); } win.myscrollbar = myscrollbar; })(window, document);