原始的滚动条确实不太美观,放在浏览器中勉强也能接收,但是在页面中的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相关推荐

  1. swiper监听滚动条_swiper Scrollbar滚动条组件详解

    本文实例为大家分享了swiper Scrollbar滚动条组件的具体代码,供大家参考,具体内容如下 1.scrollbar 为Swiper增加滚动条.类型:object. 2.el scrollbar ...

  2. elementUI 源码-打造自己的组件库,系列五:Scrollbar组件

    先上车 来吧继续阅读组件源码,Scrollbar 滚动条组件安排上 不知道elementUI官方文档上为何没有这个组件,一起来看看这个被雪藏的组件吧 先说感受:对不起,是我肤浅了,滚动条组件又秀到我了 ...

  3. Taglib原理和实现:再论El和JST

    作者: WalkingWithJava 出处: Java研究组织 问题:你想和JSTL共同工作.比如,在用自己的标签处理一些逻辑之后,让JSTL处理余下的工作. 看这个JSP例子: <% Str ...

  4. js去el的map_转:el表达式获取map对象的内容 js中使用el表达式 js 中使用jstl 实现 session.removeattribute...

    原文链接: 总结: el表达式获取map对象的内容 后端: HashMap map1 = new HashMap(); map1.put("key1","lzsb&quo ...

  5. JSP中是EL表达式与JSTL

    EL语法:${ } EL取值来自于作用域对象 1.如何从指定作用域取值(默认从最小作用域取值) pageScope.requestScope.sessionScope.applicationScope ...

  6. SpringMVC学习手册(三)------EL和JSTL(上)

    1.含义 EL:       Expression Language , 表达式语言 JSTL:   Java Server Pages Standard Tag Library, JSP标准标签库  ...

  7. java,js,jstl,EL的简单交互

    EL全名Expression Language.EL提供了在JSP脚本编制元素范围外使用运行时表达式的功能. 脚本编制元素是指页面中能够用于在JSP文件中嵌入java代码的元素. JSP标准标记库(j ...

  8. 关于ognl+struts-tag与el+jstl互相代替,以及el和jstl的学习笔记

    昨晚在晚上看了许多文章,众多大牛说OGNL性能不行云云,乍一看似乎惨不忍睹,如下图: 于是考虑是否能使用EL+JSTL代替实现前台的标签. 以最近测试用的简单留言板的查看文章页面为例,以下皆省略get ...

  9. JSP中的EL表达式详细介绍

    2019独角兽企业重金招聘Python工程师标准>>> 一.JSP EL语言定义 EL 提供了在 JSP 脚本编制元素范围外使用运行时表达式的功能.脚本编制元素是指页面中能够用于在 ...

  10. JSTL+EL表达式方法获取Oracle的Clob字段内容

    我们在页面获得数据的时候一般的类型还是很好获得的,但是一遇到Clob类型就比较麻烦,最常用的方法是用一个流将其读取出来.使用MVC框架的时候这些都是无所谓的事情,因为反正是写在java类中怎么写都行, ...

最新文章

  1. 【翻译】ASP.NET WEB API异常处理
  2. javascript控制validator
  3. 网站访问过程理解(一点记录)
  4. Leetcode 129. 求根到叶子节点数字之和 解题思路及C++实现
  5. 完整mes代码(含客户端和server端_200行代码实现基于paxos的kv存储
  6. Springmvc Bootstrap Ajax项目
  7. 你知道出现“乱码”的原因是什么吗?(4)
  8. 新浪的股票接口 c#
  9. UE4从4.15移植到4.16
  10. java开源服务框架_Java框架服务
  11. android底部导航栏软件,三步搞定android应用底部导航栏
  12. python学习之内部函数:
  13. 玩转群晖NAS套件系列三:Video Station安装使用保姆级教程!
  14. backtracking line Serach
  15. 【ACWing】1022. 宠物小精灵之收服
  16. 专家议微软黑屏:目的正当 手段未必正当
  17. DockerSwarm部署服务一直处于preparing
  18. API 网关与反向代理
  19. 第三批入围企业公示!年度TOP100智能网联供应商评选
  20. 对象.和对象[]有什么区别

热门文章

  1. 二维数组(java)
  2. 多种微量元素存在食物中
  3. 优思学院|8D和DMAIC两种方法应如何选择?
  4. java 字符串数组 转字符串_Java 中将字符串数组转换为字符串
  5. 为什么互联网流行 996 而非886、776
  6. 第五届Z·HiFi体验会隆重开幕 飞利浦影音实力耀全场
  7. js继承-构造函数继承
  8. html打照片墙的代码原理,使用html+css实现一个个人照片墙
  9. 三年磨一剑,高德地图体验优化实践总结
  10. 西安,又开始堵车了。。。