深入了解el-scrollbar
原始的滚动条确实不太美观,放在浏览器中勉强也能接收,但是在页面中的DOM元素也是这个滚动条会影响很大。element-ui库有一个组件,虽然官方文档中没有介绍,但是在源码中是存在的,在源码的packages/scrollbar文件夹中。之前一直在用,现在花点时间了解一下他是如何做到的。
明确一点,如果要直接修改浏览器滚动条的样式,一般是要有浏览器前缀的选择器才能进行修改,比如这样::-webkit-scrollbar{}。这种会出现很多兼容问题,所以来看看el-scrollbar是如何处理兼容的。
打开src/main.js直接查看,好家伙,用渲染函数这种方式定义组件的,但问题不大,基本还是能看懂的。
首先直接查看render函数是如何定义组件的
// 获取浏览器滚动条宽度
let gutter = scrollbarWidth();
// 看看有没有wrapStyle绑定的属性过来
let style = this.wrapStyle;
// 有浏览器滚动条宽度
if (gutter) {// 下面将wrapStyle标准化并加入margin属性const gutterWith = `-${gutter}px`;const gutterStyle = `margin-bottom: ${gutterWith}; margin-right: ${gutterWith};`;if (Array.isArray(this.wrapStyle)) {style = toObject(this.wrapStyle);style.marginRight = style.marginBottom = gutterWith;} else if (typeof this.wrapStyle === 'string') {style += gutterStyle;} else {style = gutterStyle;}
}
// 定义el-scrollbar__view,子组件有个插槽,就是放置el-scrollbar标签下的内容
const view = h(this.tag, {class: ['el-scrollbar__view', this.viewClass],style: this.viewStyle,ref: 'resize'
}, this.$slots.default);
// 删除掉没啥用的,既然都要用了,还需要原生干嘛
// 定义el-scrollbar__wrap,就是el-scrollbar__view的父级元素
// 并将上述标准化的wrapStyle属性绑定下来
const wrap = (<divref="wrap"style={ style }onScroll={ this.handleScroll }class={ [this.wrapClass, 'el-scrollbar__wrap', gutter ? '' : 'el-scrollbar__wrap--hidden-default'] }>{ [view] }</div>
);
let nodes = ([wrap,<Barmove={ this.moveX }size={ this.sizeWidth }></Bar>,<Barverticalmove={ this.moveY }size={ this.sizeHeight }></Bar>
]);
// 最终这里形成的模板就是
// <div class='el-scrollbar'>
// <div class= 'el-scrollbar__wrap'>
// <div class= 'el-scrollbar__view'>
// <slot></slot>
// </div>
// </div>
// <div class='el-scrollbar__bar'></div>
// <div class='el-scrollbar__bar'></div>
// </div>
return h('div', { class: 'el-scrollbar' }, nodes);
看到这里就醒悟了,实际上就是利用wrap通过 overflow:scroll;直接将滚动条显示出来,wrap的外层也就是el-scrollbar通过overflow: hidden隐藏掉促使看不见滚动条。同时这里监听了滚动,滚动函数简单的记录了几个参数,这里先不管。这里的render只是简单提了一下el-scrollbar__bar,那么我们需要详细看看,在src/bar.js中
const { size, move, bar } = this;return (<divclass={ ['el-scrollbar__bar', 'is-' + bar.key] }onMousedown={ this.clickTrackHandler } ><divref="thumb"class="el-scrollbar__thumb"onMousedown={ this.clickThumbHandler }style={ renderThumbStyle({ size, move, bar }) }></div></div>
);
这个就比较简单了,通过bar.key去更改样式,实际上就是显示自定义滚动条还是不显示自定义滚动条,关键在于el-scrollbar__thumb,这个div就是能够拖动的那个div,所以很关键。可以看到这两个都绑定了一个监听鼠标按下的函数,基本上就是处理拖动的时候的数据的变化。
clickThumbHandler(e) {// prevent click event of right buttonif (e.ctrlKey || e.button === 2) {return;}this.startDrag(e);this[this.bar.axis] = (e.currentTarget[this.bar.offset] - (e[this.bar.client] - e.currentTarget.getBoundingClientRect()[this.bar.direction]));
},clickTrackHandler(e) {const offset = Math.abs(e.target.getBoundingClientRect()[this.bar.direction] - e[this.bar.client]);const thumbHalf = (this.$refs.thumb[this.bar.offset] / 2);const thumbPositionPercentage = ((offset - thumbHalf) * 100 / this.$el[this.bar.offset]);this.wrap[this.bar.scroll] = (thumbPositionPercentage * this.wrap[this.bar.scrollSize] / 100);
},startDrag(e) {e.stopImmediatePropagation();this.cursorDown = true;on(document, 'mousemove', this.mouseMoveDocumentHandler);on(document, 'mouseup', this.mouseUpDocumentHandler);document.onselectstart = () => false;
},mouseMoveDocumentHandler(e) {if (this.cursorDown === false) return;const prevPage = this[this.bar.axis];if (!prevPage) return;const offset = ((this.$el.getBoundingClientRect()[this.bar.direction] - e[this.bar.client]) * -1);const thumbClickPosition = (this.$refs.thumb[this.bar.offset] - prevPage);const thumbPositionPercentage = ((offset - thumbClickPosition) * 100 / this.$el[this.bar.offset]);this.wrap[this.bar.scroll] = (thumbPositionPercentage * this.wrap[this.bar.scrollSize] / 100);
},mouseUpDocumentHandler(e) {this.cursorDown = false;this[this.bar.axis] = 0;off(document, 'mousemove', this.mouseMoveDocumentHandler);document.onselectstart = null;
}
这里可以看出,el-scrollbar__thumb用了html5的拖拽然后去计算拖拽的距离,然后更新视图的位置,视图的位置通过renderThumbStyle函数中的定义的css的translate属性进行变换的。
handleScroll() {const wrap = this.wrap;this.moveY = ((wrap.scrollTop * 100) / wrap.clientHeight);this.moveX = ((wrap.scrollLeft * 100) / wrap.clientWidth);
},
上述提到的滚动函数,可以看出,warp.scrollTop的值的变换是原始滚动就会改变的,这里这是将滚动的值拿出来赋值给this.moveY促使自定义的滚动条也发生移动而已。
深入了解el-scrollbar相关推荐
- swiper监听滚动条_swiper Scrollbar滚动条组件详解
本文实例为大家分享了swiper Scrollbar滚动条组件的具体代码,供大家参考,具体内容如下 1.scrollbar 为Swiper增加滚动条.类型:object. 2.el scrollbar ...
- elementUI 源码-打造自己的组件库,系列五:Scrollbar组件
先上车 来吧继续阅读组件源码,Scrollbar 滚动条组件安排上 不知道elementUI官方文档上为何没有这个组件,一起来看看这个被雪藏的组件吧 先说感受:对不起,是我肤浅了,滚动条组件又秀到我了 ...
- Taglib原理和实现:再论El和JST
作者: WalkingWithJava 出处: Java研究组织 问题:你想和JSTL共同工作.比如,在用自己的标签处理一些逻辑之后,让JSTL处理余下的工作. 看这个JSP例子: <% Str ...
- js去el的map_转:el表达式获取map对象的内容 js中使用el表达式 js 中使用jstl 实现 session.removeattribute...
原文链接: 总结: el表达式获取map对象的内容 后端: HashMap map1 = new HashMap(); map1.put("key1","lzsb&quo ...
- JSP中是EL表达式与JSTL
EL语法:${ } EL取值来自于作用域对象 1.如何从指定作用域取值(默认从最小作用域取值) pageScope.requestScope.sessionScope.applicationScope ...
- SpringMVC学习手册(三)------EL和JSTL(上)
1.含义 EL: Expression Language , 表达式语言 JSTL: Java Server Pages Standard Tag Library, JSP标准标签库 ...
- java,js,jstl,EL的简单交互
EL全名Expression Language.EL提供了在JSP脚本编制元素范围外使用运行时表达式的功能. 脚本编制元素是指页面中能够用于在JSP文件中嵌入java代码的元素. JSP标准标记库(j ...
- 关于ognl+struts-tag与el+jstl互相代替,以及el和jstl的学习笔记
昨晚在晚上看了许多文章,众多大牛说OGNL性能不行云云,乍一看似乎惨不忍睹,如下图: 于是考虑是否能使用EL+JSTL代替实现前台的标签. 以最近测试用的简单留言板的查看文章页面为例,以下皆省略get ...
- JSP中的EL表达式详细介绍
2019独角兽企业重金招聘Python工程师标准>>> 一.JSP EL语言定义 EL 提供了在 JSP 脚本编制元素范围外使用运行时表达式的功能.脚本编制元素是指页面中能够用于在 ...
- JSTL+EL表达式方法获取Oracle的Clob字段内容
我们在页面获得数据的时候一般的类型还是很好获得的,但是一遇到Clob类型就比较麻烦,最常用的方法是用一个流将其读取出来.使用MVC框架的时候这些都是无所谓的事情,因为反正是写在java类中怎么写都行, ...
最新文章
- 【翻译】ASP.NET WEB API异常处理
- javascript控制validator
- 网站访问过程理解(一点记录)
- Leetcode 129. 求根到叶子节点数字之和 解题思路及C++实现
- 完整mes代码(含客户端和server端_200行代码实现基于paxos的kv存储
- Springmvc Bootstrap Ajax项目
- 你知道出现“乱码”的原因是什么吗?(4)
- 新浪的股票接口 c#
- UE4从4.15移植到4.16
- java开源服务框架_Java框架服务
- android底部导航栏软件,三步搞定android应用底部导航栏
- python学习之内部函数:
- 玩转群晖NAS套件系列三:Video Station安装使用保姆级教程!
- backtracking line Serach
- 【ACWing】1022. 宠物小精灵之收服
- 专家议微软黑屏:目的正当 手段未必正当
- DockerSwarm部署服务一直处于preparing
- API 网关与反向代理
- 第三批入围企业公示!年度TOP100智能网联供应商评选
- 对象.和对象[]有什么区别