zoukankan      html  css  js  c++  java
  • 基于Vue的事件响应式进度条组件

    写在前面

    找了很多 Vue 进度条组件!,都不包含拖拽和点击事件,input range倒是原生包含input和change事件,但是直接基于input range做进度条的话,样式部分需要做大量调整和兼容性处理。即使做好了,将来需要修改外观,又是一番折腾。

    基于以上两个原因,做了一个可以响应input和change事件(即一个是拖动进度条到某处,一个是在进度条某位置点击使其值变为该位置)的div实现的Vue组件,这样既满足了对进度条事件的需求,也带来了如有需求变动,样式修改很方便的好处。

    事件响应式进度条的应用场景主要是自定义video播放器的进度条。

    效果图

    以上就是可以利用本组件实现的一些效果,他们都能响应input和change两种事件。

    首先是模板部分

    认真看一下上图,怎么构造HTML模板还是需要一番考虑的,我也是改了好几次,最后定的这个结构。首先有一层外包div就不说了。然后外包div下面就一个class = 'progress'的div,这个div内部的div是表示进度条已划过部分(class="left"),class="left"这个div内部又包含一个div来表示我们可以拖动的滑块小球。

    说一下好处,这样的结构,做出来的样式,在页面检查元素的时候,能够清晰看到每个div和页面上展示的部分是重合的。

    如果你的进度条 表示整个长度的div、表示左半部分的div、表示滑块的div这三部分不是我这种嵌套结构,而是兄弟节点关系,你就得用样式做相对定位,让后两个兄弟节点上移到第一个兄弟元素的位置,这样,检查元素的时候,进度条下面的其他组件的盒子就会浸透到进度条的区域。虽然用户不会检查元素,但是时间久了之后也不方便程序员自己观察,不是吗。

    也就是说,我们都希望HTML结构表达的元素和检查元素的时候显示的每个元素的占位是一致的。这也算是对你的HTML结构是否构造合理的一个评价指标

    
    <template>
        <div class="progress-wrapper" :style="wrapStyle">
            <div class="progress" @mousedown="mousedownHandler" @mouseover="mouseoverHandler"
                 @mousemove="mousemoveHandler" @mouseup="mouseupHandler" :style="pBarStyle">
                <div class="left" :style="leftStyle">
                    <div class="ball" :style="ballStyle"></div>
                </div>
                <slot></slot>
            </div>
        </div>
    </template>
    

    js部分

    对现在就有需求使用这个带事件的进度条的同学来说,看看这部分,可以帮助你自己修改、完善它。

    而对于想要先试用该组件的同学,则可以先不看这部分,等你用到发现该组件功能不足的时候,再看这部分代码也不迟。

    
    export default {
            name: 'ProgressBar',
            props: {
                leftBg: String,
                bgc: String,
                ballBgc: String,
                height: String,
                 String,
                max: {
                    type: Number,
                    default: 100,
                },
                min: {
                    type: Number,
                    default: 0,
                },
                value: {
                    type: Number,
                    default: 36,
                },
            },
            data: function () {
                return {
                    pValue: this.value,
                    pMax: this.max,
                    pMin: this.min,
                    wrapStyle: {
                        'width': this.width,
                    },
                    pBarStyle: {
                        'backgroundColor': this.bgc,
                        'height': this.height,
                    },
                    leftStyle: {
                        'width': this.progressPercent + '%',
                        'background': this.leftBg,
                        'height': this.height,
                    },
                    ballStyle: {
                        'backgroundColor': this.ballBgc,
                        'height': this.height,
                        'width': this.height,
                        'borderRadius': parseInt(this.height) / 2 + 'px',
                        'right': - parseInt(this.height) / 2 + 'px',
                    },
                    // 标记是否按下鼠标
                    isMouseDownOnBall: false,
                }
            },
            computed: {
                progressPercent(){
                    return (this.pValue - this.pMin) / (this.pMax - this.pMin) * 100;
                },
                progressElement(){
                    return this.$el.getElementsByClassName('progress')[0];
                },
            },
            methods: {
                mousedownHandler(e){
                    if(e.which === 1){
                        this.isMouseDownOnBall = true;
                    }
                },
                mousemoveHandler(e){
                    if(this.isMouseDownOnBall === true){
                        // 修改进度条本身
                        let decimal = (e.clientX - this.$el.offsetLeft) / this.progressElement.clientWidth;
                        let percent = decimal * 100;
                        this.leftStyle.width = percent + '%';
                        // 修改value
                        this.pValue = this.pMin + decimal * (this.pMax - this.pMin);
                        this.$emit('pbar-drag', this.pValue, percent);
                    }
                },
                mouseupHandler(e){
                    if(this.isMouseDownOnBall){
                        // 修改进度条本身
                        let decimal = (e.clientX - this.$el.offsetLeft) / this.progressElement.clientWidth;
                        let percent = decimal * 100;
                        this.leftStyle.width = percent + '%';
                        // 修改value
                        this.pValue = this.pMin + decimal * (this.pMax - this.pMin);
                        this.$emit('pbar-seek', this.pValue, percent);
    
                        this.isMouseDownOnBall = false;
                    }
                },
                mouseoverHandler(e){
                    // 没有按左键进入进度条
                    if(e.which === 0){
                        this.isMouseDownOnBall = false;
                    }
                }
            },
            watch: {
                max(cur, old){
                    this.pMax = cur;
                },
                min(cur, old){
                    this.pMin = cur;
                },
                value(cur, old){
                    this.pValue = cur;
                },
                progressPercent(cur, old){
                    this.leftStyle.width = cur + '%';
                }
            },
            mounted(){
                // 数据验证
                if(this.max < this.min){
                    console.error("max can't less than min !");
                }
                // 初始百分比
                this.leftStyle.width = (this.pValue - this.pMin) / (this.pMax - this.pMin) * 100 + '%';
            },
        }
    

    安装、使用

    地址

    代码库地址在GitHub

    安装、使用

    
    
    npm install vue-draggable-progressbar --save
    
    import progressBar from 'vue-draggable-progressbar'
    

    用例:

    
    <progress-bar ref="aa"></progress-bar>
    
    <progress-bar width="40%" leftBg="greenyellow" bgc="#ccc" ballBgc="red"></progress-bar>
    
    <progress-bar width="60%" leftBg="linear-gradient(to right, yellow, pink)" bgc="#ccc" ballBgc="red"></progress-bar>
    
    <progress-bar width="80%" leftBg="yellow" bgc="#ccc" ballBgc="red" height="30px"></progress-bar>
    
    <progress-bar leftBg="greenyellow" bgc="#ccc" ballBgc="rgba(255,0,0,0.2)" height="40px"></progress-bar>
    
    <progress-bar leftBg="greenyellow" bgc="#ccc" ballBgc="red" :max="max" :value="value" :min="min"
                  @pbar-drag="drag" @pbar-seek="seek"></progress-bar>
    
    

    组件props

    • leftBg:进度条已划过部分背景色
    • bgc:进度条还未划过部分背景色
    • ballBgc:滑块背景色
    • width:进度条占父组件的宽度百分比,传百分比数值
    • height:进度条高度,传像素值

    事件

    • pbar-drag: 拖动进度条时触发,回传value值和百分比值
    • pbar-drag: 点击进度条某一位置时触发,回传value值和百分比值

    最后

    如果本文对你有帮助,请不要吝啬手中的点赞哟。
    编程贵在实践,赶紧行动起来吧!

    关于作者

    技术博客 || GitHub || 掘金主页

    原文地址:https://segmentfault.com/a/1190000013123304

  • 相关阅读:
    stl_heap
    关于随机数 C++
    关于if语句的细节
    C++关于智能指针
    sqlyog
    win10 64位 汇编环境
    Qt 乱码
    Vux使用经验
    Flex布局新旧混合写法详解
    【原】npm 常用命令详解
  • 原文地址:https://www.cnblogs.com/lalalagq/p/9923627.html
Copyright © 2011-2022 走看看