前言
最近看到一些博客网址发现网站顶部有一个进度条。随着你滑轮的滑动,进度条变成变短。
思考了一下无法就是添加一个div,div一开始的宽度是0,随着滑轮的滚动而变得变小。但是实际写逻辑的时候发现还行有很多细节的。
思路(问题)
div的宽度和滚轮滚动之间的关系
这里用到了几个值:
- clientHeight:容器的可视高度
- clientWidth :容器的可视宽度
- scrollHeight:元素内容的高度,包括溢出的部分
- scrollTop:滚动条的偏移量
1、先计算滚动条最多可以滚动的距离
打印了一下值,最大距离是:scrollHeight - clientHeight
2、关系
div的宽度等于 clientWidth * (scrollTop / maxScrollTop)
如何插入div
1、什么时候插入div
一定是容器出现纵向滚动条时才插入,上面已经计算了最大滚动距离,如果大于0,说明有滚动条
2、插入到哪里
div肯定要放到容器的最前面,所以要用insertBefore
而不是appendChild
。insertBefore
方法第一个参数是要插入的节点,第二个参数是目标节点。
结论
当出现滚动条,并且有第一个子节点的时候插入
添加样式
最开始的时候是通过classList.add
添加类的方式来添加样式,但是类添加上了实际上并没有生效。所以这里采用style
方式添加样式。
代码
<template>
<div v-read-progress="'#3EAF7C'" class="main">
<div v-for="i in 40" :key="i" class="number">数字是:{{ i }}</div>
</div>
</template>
<script>
export default {
directives: {
readProgress: {
// vue3的指令,与vue2稍微有点不同
mounted(el,binding) {
// 获取第一个子节点
let firstChild = el.firstElementChild;
// console.log(firstChild);
// 容器的可视高度
let clientHeight = el.clientHeight;
// 元素内容的高度,包括溢出的不可见内容
let scrollHeight = el.scrollHeight;
// el.scrollTop滚动条的偏移量
// 技术滚动条的最大偏移量
let maxScrollTop = scrollHeight - clientHeight;
// 插入一个div
if(maxScrollTop > 0 && firstChild) {
// 当出现滚动条并且容器内存在子节点时插入一个div
let div = document.createElement('div');
// 要插入的节点,目标节点
el.insertBefore(div,firstChild);
// 添加样式,最初是打算通过添加类的方式添加样式,但是添加上类,样式不生效
div.style.width = '0px';
div.style.height = '5px';
div.style.background = binding.value;
div.style.position = 'absolute';
div.style.transition = 'all';
// 绑定鼠标滑轮事件
el.addEventListener('mousewheel',event => {
// console.log(event,el.scrollTop);
// div的宽度=容器的可视宽度(这里不考虑有横向滚动条的情况)* (偏移量 / 最大偏移量)
let w = el.clientWidth * el.scrollTop / maxScrollTop;
div.style.width = parseInt(w) + 'px';
});
}
}
}
},
data() {
return {
};
},
methods: {
}
};
</script>
<style scoped lang="scss">
.main{
width: 600px;
height: 600px;
border: 1px solid red;
overflow-y: auto;
.number{
height: 40px;
width: 100%;
line-height: 40px;
border-bottom: 1px solid red;
}
}
</style>