vue指令实现阅读进度条

前言

最近看到一些博客网址发现网站顶部有一个进度条。随着你滑轮的滑动,进度条变成变短。
思考了一下无法就是添加一个div,div一开始的宽度是0,随着滑轮的滚动而变得变小。但是实际写逻辑的时候发现还行有很多细节的。

思路(问题)

div的宽度和滚轮滚动之间的关系

这里用到了几个值:

  • clientHeight:容器的可视高度
  • clientWidth :容器的可视宽度
  • scrollHeight:元素内容的高度,包括溢出的部分
  • scrollTop:滚动条的偏移量

1、先计算滚动条最多可以滚动的距离

打印了一下值,最大距离是:scrollHeight - clientHeight

2、关系

div的宽度等于 clientWidth * (scrollTop / maxScrollTop)

如何插入div

1、什么时候插入div
一定是容器出现纵向滚动条时才插入,上面已经计算了最大滚动距离,如果大于0,说明有滚动条

2、插入到哪里
div肯定要放到容器的最前面,所以要用insertBefore而不是appendChildinsertBefore方法第一个参数是要插入的节点,第二个参数是目标节点。

结论
当出现滚动条,并且有第一个子节点的时候插入

添加样式

最开始的时候是通过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>

效果

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无知的小菜鸡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值