宝哥软件园

基于vue.js2.x的虚拟滚动条示例代码

编辑:宝哥软件园 来源:互联网 时间:2021-09-01

前言

记得有一次浏览一个开源的cms项目,发现这个项目左侧的菜单已经超过了窗口的宽度。我想知道为什么没有滚动条。然后我仔细一看,发现它的左侧有一个小div。然后我试着拖动它,发现它就像原来的滚动条一样!通过查看它的源代码,我发现这个滚动条叫做slimScroll。然后我去了它的github仓库,研究了一下源代码,给我的感觉就是可以做同样的滚动条!通过vue实现!

设计

好了,现在让我们开始设计滚动条的步骤:

设计滚动条dom

首先要考虑的是,如果:想要滚动你需要滚动的内容,第一点就是它的父dom必须有固定的长度和宽度,也就是多余的部分要隐藏,也就是增加了一个style : overflow: hidden,所以我们把要滚动的内容包装起来,让它的长度和宽度等于父dom,然后一个style叫做overflow: hidden,这个包的元素叫做SCR

其次,我们知道我们应该像原生滚动条一样强大!需要设计水平滚动条和垂直滚动条,属于兄弟节点之间的关系。因为滚动条的存在不能使原样式出现排版错误,并且支持上下左右控制其位置,所以滚动条的位置必须是绝对的。好的,我们称水平滚动条:为hBar,垂直滚动条3360为VBAR。

最后:我们设计了scrollPanel,vBar,hBar,我们需要一个父div来包装它们,然后添加一个:position: relative的样式

实践

设计组件结构

首先,我们的插件总共有四个组件,其中三个是子组件,一个是父组件,即: vueScroll(父组件)、scrollPanel(包装要滚动内容的子组件)、vBar(垂直滚动条)和hBar(水平滚动条)

其次,让我们设计每个组件的功能。这里的组件分为控制层组件和显示组件(熟悉react的同学应该对它们有所了解)。显示层组件只完成: vBar、hBar和scrollPanel的显示功能。控制层组件有点类似于cpu,可以控制子组件的各种状态,比如宽度、高度、颜色、透明度、位置等等。控制层组件是: vueScroll。

具体实现

hBar/vBar

HBar/vBar分别是水平滚动条和垂直滚动条,它们的功能基本相同,所以我们把它们放在一起,这里以vBar为例。

Props从父组件接收属性,具体为:

{height :vm.state.height' px ',//滚动条:vm.ops.width的高度宽度,//滚动条位置:' absolute '的宽度,背景:vm.ops.background,//滚动条top: vm.state.top 'px '的背景颜色,//滚动条3360 ' opx . 5s '的高度过渡,//消失/显示时间光标: '指针',//opa city 3360 VM . state。

.render(_c){ return _c(//.{ mouseenter:函数(e) { vm。$ emit(' showVBar ');//触发父组件事件并显示滚动条}}//.)},其中状态代表状态,可以在运行时更改,而ops是配置参数,由用户传输。

scrollPanel

用滚动内容打包组件,样式应该设置为: overflow: hidden。

1.风格

var style=VM . scrollcontentstyle;style.overflow=' hidden//.{style: style} //.2.事件

//.render(_c) { //. { mouse enter : function(){ VM。$ emit(' ShowBar ');},mouseleave:函数(){ vm。$ emit(' HideBar ');} } //.} //.vuescroll

控制组件。控制子组件的显示状态,添加各种监听事件等。

1.获取组件的dom元素,获取dom的实时信息。

//.initEl(){ this。滚动面板。El=这个.$ refs[' vuescrolpanel ']这个$ refs[' vuescrolpanel '].$ elthis.vScrollBar.el=this .$refs['vScrollBar']这个$refs['vScrollBar'].$ elthis.hScrollBar.el=this .$refs['hScrollBar']这个$refs['hScrollBar'].$ el} //.2、显示滚动条

显示滚动条,包括显示水平滚动条和显示垂直滚动条,这里以显示垂直滚动条为例:

//.变化的温度;var deltaY={ deltaY : this。vscrollbar。行动组。deltaY//获取用户配置的deltaY };if(!这个。ismouseleavepanel | |这个。vscrollbar。行动组。keepshow){ if((this。vscrollbar。国家。高度=温度=这个。getvbarheight(deltaY))){//判断条件//重新设置滚动条的状态这个。vscrollbar。国家。top=这个。resizevbartop(temp);这个。vscrollbar。国家。高度=温度。身高;这个。vscrollbar。国家。不透明度=这个。vscrollbar。行动组。不透明度;} } //.3、获取滚动条的高度

因为数字正射影像图元素的高度不是固定的,所以你要实时地获取数字正射影像图真实的高度,滚动条的高度计算公式如下:

var height=数学。max(滚动面板高度/(滚动面板滚动高度/滚动面板高度),这个。vscrollbar。minbar高度);即:滚动条的高度:scrollPanel的高度==scrollPanel的高度:dom元素高度

4、resizeVBarTop,为了防止误差,并且可以求出滚动条距离父元素的高度。

resizeVBarTop({height,scrollPanelHeight,scrollPanelHeight,deltaY}) { //cacl最后一个高度第一个var last height=scrollpanel滚动高度-scrollpanel height-this。滚动面板。埃尔。滚动顶部;if(LastHeight this。精度){ LastHeight=0;} var time=数学。ABS(数学。天花板(最后高度/Y));var top=滚动面板高度-(height(time * this。vscrollbar。inner deltay));返回顶部;}5、监听滚轮滚动的事件。

//. { wheel: vm.wheel } //.车轮(e){ var VM=这个;虚拟机。show vbar();虚拟机。滚动条(例如增量0?1 : -1, 1);e . stopperpagation();} //.6、监听滚动条拖拽事件

listenVBarDrag:函数(){ var VM=this var y;var _ y;函数move(e){ _ y=e . Pagey;var _ delta=_ y-y;虚拟机。scrolvbar(_ delta 0?1 : -1,数学。ABS(_ delta/VM。vscrollbar。inner deltay));y=_ y}函数t(e){ var deltaY={ delta y : VM。vscrollbar。行动组。deltaY };if(!虚拟机。getvbarheight(deltaY)){ return;} VM . mouse down=truey=e.pageY//记录初始的Y的位置虚拟机。show vbar();文件。addeventlistener('鼠标移动',移动);文件。addeventlistener('鼠标向上',函数{虚拟机。鼠标按下=假;虚拟机。hide vbar();文件。removeeventlistener('鼠标移动,移动');});}这个。听众。推送({ DOM : VM。vscrollbar。El,event: t,键入: '鼠标向下' });虚拟机。vscrollbar。埃尔。addeventlistener('鼠标按下,t);//把事件放到数组里面,等销毁之前移除掉注册的时间。 }7、适配移动端,监听触控事件。原理跟拖拽事件差不多,无非就是多了个判断,来判断当前方向是x还是y。

listenPanelTouch:函数(){ var vm=thisvar panel=this。滚动面板。El;var x,y;var _x,_ y;函数移动(e){如果(e)触摸。长度){ var touch=e . touch[0];_ x=touch . pagex _ y=touch . pageyvar _ delta=void 0;var _ deltaX=_ x-x;var _ deltaY=_ y-y;if(数学。ABS(_ deltaX)数学。ABS(_ deltaY)){ _ delta=_ deltaX;虚拟机。scrolhbar(_ delta 0?-1 : 1,数学。ABS(_ delta/VM。hscrollbar。inner deltax));} else if(数学。ABS(_ deltaX)数学。ABS(_ deltaY)){ _ delta=_ deltaY;虚拟机。scrolvbar(_ delta 0?-1 : 1,数学。ABS(_ delta/VM。vscrollbar。inner deltay));} x=_ xy=_ y} }函数t(e){ var deltaY={ delta y : VM。vscrollbar。行动组。deltaY };var deltaX={ deltaX : VM。hscrollbar。行动组。deltaX };if(!vm.getHBarWidth(deltaX)!虚拟机。getvbarheight(deltaY)){ return;}如果(例如触摸。length){ e . stopperpagation();var touch=e . touch[0];VM . mouse down=truex=touch . page xy=touch . page yvm。show bar();潘内尔。addeventlistener(' touch move ',move);潘内尔。addeventlistener(' touch end ',函数{虚拟机。鼠标按下=假;虚拟机。HideBar();潘内尔。removeeventlistener(' touch move ',move);});} } pannel。addeventlistener(' touch start ',t);这个。听众。push({ DOM : pannel,event: t,type : ' touch start ' });}8、滚动内容

滚动内容的原理无非就是改变scrollPanel的滚动顶部/滚动底部来达到控制内容上下左右移动的目的。

scrollVBar:函数(pos,time) { //0向下滚动到0向上滚动到var top=这个。vscrollbar。国家。顶部;var滚动面板高度=getComputed(这。滚动面板。El,' height ').替换(' px ',' ');var滚动面板滚动高度=这个。滚动面板。埃尔。滚动高度;var滚动面板滚动顶部=这个。滚动面板。埃尔。滚动顶部;可变高度=这个。vscrollbar。国家。身高;var innerdeltaY=this。vscrollbar。内三角洲;var deltaY=这个。vscrollbar。行动组。deltaYif(!((0位置顶部=0)| |(滚动面板高度=0位置顶部高度)| |(数学。ABS(滚动面板滚动高度-滚动面板高度)这个。精度){ var Top=Top pos *内部差值*时间;var滚动顶部=滚动面板滚动顶部pos * deltaY *时间;if(位置0) { //滚动IP这个。vscrollbar。国家。Top=数学。最大值(0,顶部);这个。滚动面板。埃尔。滚动顶部=数学。max(0,滚动顶部);} else if (pos 0) { //向下滚动这个。vscrollbar。国家。Top=数学。最小值(滚动面板高度-高度,顶部);这个。滚动面板。埃尔。滚动顶部=数学。min(滚动面板滚动高度-滚动面板高度,滚动顶部);} } //这些是传递给父组件的监听滚动的函数的var内容={ };var bar={ };定义变量进程=' ';内容。残差=(滚动面板滚动高度-滚动面板滚动顶部-滚动面板高度);内容。scroll=滚动面板滚动顶部;酒吧。滚动=这个。vscrollbar。国家。顶部;酒吧。残差=(scrollpanel height-this。vscrollbar。国家。顶上这个。vscrollbar。国家。高度);酒吧。高度=这个。vscrollbar。国家。身高;进程=bar。滚动/(滚动面板高度栏。高度);bar.name=' vBarcontent.name='内容这个$emit('vscroll ',栏,内容,进程);},9、销毁注册的事件。

刚才我们已经把注册事件放到听众数组里面了,我们可以在在毁灭之前钩子里将他们进行销毁。

//移除注册的事件this.listeners.forEach(函数(项){ item。多姆。removeeventlistener(项。事件,项目。类型);});运行截图

个人电脑端运行截图如下图所示:

注册监听事件以后如下图所示:

在手机上运行截图:

可以看出,跟原生滚动条表现效果一致。

结语感悟

以上,我基本完成了滚动条的设计。首先感谢掘金给了我这样的分享平台,然后感谢slimScroll的作者给了我这样的想法。完成这个插件后,我对dom元素的scrollWidth、scrollHeigh、scrollTop和scrollLeft有了更多的了解。最后,我附上github项目地址

以上部分是这个组件的核心源代码。希望对大家的学习有帮助,希望大家多多支持我们。

更多资讯
游戏推荐
更多+