scrollbar 源码解析的时候,我们不是为了弄懂它的每一行代码,但是我们必须学会它这种写scrollbar的思路,以及写法中充分利用vue的语法结构的学习。只有这样我们才能真正知道,写组件,尤其是写可以被广泛使用的公用组件的套路。ok,废话少说,开始进入枯燥的源码学习。请大家怀着一颗仁慈和包容的心态继续往下看,Come on,干起来!!!!
可以页面想象成一个长长的盒子,我们看到的是个视口。视口是不动的,盒子是移动的,当盒子向下滚动时,视口中所看到的盒子正在向下滚动。同样的,滚动块里面的滑块也往下移动同样比例的距离。
image image文件夹结构
scrollbar组件在 package/scrollbar/index.js中注册,其中package/scrollbar/src 是代码的核心部分,入口文件是 main.js。
使用如下
image image大家详细看一下注释,wrap是视口,view即内容可以滚动,horizontal 和 vertical是自定义滚动条。 下面开始撸代码,大家打起精神。走起!!!!!
main.js
main.js默认导出一个对象,接收一系列配置。
name: 'ElScrollbar',
components: {
// 滚动条组件,拥有水平与垂直两种形态
Bar
},
props: {
native: Boolean, // 是否使用原生滚动条,即不附加自定义滚动条
wrapStyle: {}, // wrap的内联样式
wrapClass: {}, // wrap的样式名
viewClass: {}, // view的样式名
viewStyle: {}, // view的内联样式
noresize: Boolean, // 当container尺寸发生变化时,自动更新滚动条组件的状态
tag: { // 组件最外层的标签属性,默认为 div
type: String,
default: 'div'
}
},
data() {
return {
sizeWidth: '0', // 水平滚动条的宽度
sizeHeight: '0', // 垂直滚动条的高度
moveX: 0, // 垂直滚动条的移动比例
moveY: 0 // 水平滚动条的移动比例
};
},
组件在render函数中生成结构。
tips: 如果在.vue文件中同时存在templete和 render 函数,组件实例会先取 template模板来渲染组件模板,而不是采用render函数
render函数一开始会通过scrollbarWidth 方法来计算当前浏览器的滚动条宽度
render(h) {
// 获取浏览器的滚动条宽度
let gutter = scrollbarWidth();
// wrap内联样式
let style = this.wrapStyle;
...
scrollbarWidth 方法在scrollbar-width.js 中被默认导出
import Vue from 'vue';
// 闭包变量,用于记录滚动条宽度
let scrollBarWidth;
export default function() {
// 如果在服务端运行,返回 0
if (Vue.prototype.$isServer) return 0;
// 如存在滚动条宽度,直接返回
if (scrollBarWidth !== undefined) return scrollBarWidth;
// 创建outer标签并隐藏
const outer = document.createElement('div');
outer.className = 'el-scrollbar__wrap';
outer.style.visibility = 'hidden';
outer.style.width = '100px';
outer.style.position = 'absolute';
outer.style.top = '-9999px';
document.body.appendChild(outer);
// 记录没有滚动内容的宽度
const widthNoScroll = outer.offsetWidth;
// 设置外层div滚动属性
outer.style.overflow = 'scroll';
// 创建inner标签,并追加到outer标签中
const inner = document.createElement('div');
inner.style.width = '100%';
outer.appendChild(inner);
// 此时outer已经可以滚动,记录下inner元素的宽度
const widthWithScroll = inner.offsetWidth;
// 销毁outer元素
outer.parentNode.removeChild(outer);
// 滚动条宽度 = 没有滚动条时的outer宽度 减去 有滚动条的outer中的inner宽度
scrollBarWidth = widthNoScroll - widthWithScroll;
// 返回滚动条宽度
return scrollBarWidth;
};
得到滚动条方法会进行以下步骤
1、创建outer 容器,并记录outer容器offsetwidth
2、设置outer容器overflow:scroll,并新建inner容器,追加到outer容器下
3、此时outer容器会带着滚动条,记录inner容器的offsetwidth 宽度
网友评论