美文网首页让前端飞程序员前端开发那些事
说说如何在 Vue.js 中实现数字输入组件

说说如何在 Vue.js 中实现数字输入组件

作者: deniro | 来源:发表于2018-12-30 20:20 被阅读9次

    我们对普通输入框进行扩展,实现一个可快捷输入数字组件。

    首先制定规则:

    • 只能输入数字。
    • 设计两个快捷按钮,可直接在当前值的基础上增 1 或者减 1。
    • 数字输入组件可设置初始值、最大值与最小值。

    接着,规划好 API。一个 Vue.js 组件最重要的 3 个部分就是 props、events 以及 slot,我们需要定义这三个部分的命名以及业务规则。这个组件比较简单,所以我们只用到 props 与 events。

    1 基础版

    html:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>数字输入组件</title>
    </head>
    <body>
    <div id="app">
        <number-input v-model="value" :min="0" :max="6"></number-input>
    </div>
    <script src="https://cdn.bootcss.com/vue/2.2.2/vue.min.js"></script>
    <script src="number.js"></script>
    <script>
        var app = new Vue({
            el: '#app',
            data: {
                value: 3
            }
        });
    </script>
    </body>
    </html>
    

    这里,我们使用了 v-model,双向绑定了 value。

    number.js:

    /**
     * 是否为数字
     * @param val
     * @returns {boolean}
     */
    function isNum(val) {
        return (/^[0-9]*$/).test(val);
    }
    
    /**
     * 数字输入组件
     */
    Vue.component('number-input', {
        template: '\
        <div class="number-input">\
            <input \
                type="text"\
                :value="currentVal"\
                @change="change">\
            <button\
                @click="down"\
                :disabled="currentVal<=min">-</button>\
            <button\
                @click="up"\
                :disabled="currentVal >=max">+</button>\
        </div>',
        props: {//校验
            //最大值
            max: {
                type: Number,
                default: Infinity
            },
            //最小值
            min: {
                type: Number,
                default: -Infinity
            },
            //初始值
            value: {
                type: Number,
                default: 0
            }
        },
        data: function () {
            return {
                currentVal: this.value
            }
        },
        watch: {
            currentVal: function (val) {
                console.log("currentVal:" + this.currentVal);
                this.$emit('input',val);
            },
            value: function (val) {//更新 currentVal
                this.update(val);
            }
        },
        methods: {
            /**
             * 更新
             * @param val
             */
            update: function (val) {
                //让输入的值在限定范围内
                if (val > this.max) {
                    val = this.max;
                }
                if (val < this.min) {
                    val = this.min
                }
                this.currentVal = val;
            },
            /**
             * 减少
             */
            down: function () {
                if (this.currentVal <= this.min) {
                    return;
                }
                this.currentVal -= 1;
            },
            /**
             * 增长
             */
            up: function () {
                if (this.currentVal >= this.max) {
                    return;
                }
                this.currentVal += 1;
            },
            /**
             * 如果输入的值,
             * @param event
             */
            change: function (event) {
                var val = event.target.value.trim();//获取输入值
    
                if (isNum(val)) {//赋值 currentVal
                    val = Number(val);
                    this.currentVal = val;
    
                    //超出限定范围时,规整
                    var max = this.max;
                    var min = this.min;
                    if (val > max) {
                        this.currentVal = max;
                    } else if (val < min) {
                        this.currentVal = min;
                    }
                } else {//还原为 currentVal
                    event.target.value = this.currentVal;
                }
            }
        },
        mounted: function () {
            //对初始值进行范围限定
            this.update(this.value);
        }
    });
    

    这里,我们专门定义了一个 number.js,用于定义数字输入组件。

    在 number.js 中,我们做了如下工作:

    1. 利用正则表达式 ,定义了一个判断 “是否为数字” 的函数。
    2. 在模板定义中,我们定义了一个输入框以及两个按钮,首先在 input 中绑定了 currentVal 数据以及原生的 change 事件。接着,定义了递增与递减按钮,每个按钮都绑定了相应的事件,还绑定了 disabled 属性,这样当输入的值超出范围时,按钮就会置灰不可用。
    3. 在定义的 change() 方法中,先获取输入值,然后判断是否为数字。如果是数字,则赋值给 currentVal;如果不是数字,则还原为 currentVal,这样可以保证组件的内容始终是数字。
    4. 接着在 props 中,对每一个参数(最大值、最小值、初始值)定义了相应的校验规则。这样就可以在父组件中初始化这个数字输入组件啦O(∩_∩)O~
    5. 因为 Vue.js 组件时单向数据流,所以不能在组件内部修改之前在 props 中定义的 value。我们可以在 data 函数中,声明一个 currentVal,并把 props 中定义的 value 值赋给它。这样就实现了组件初始化时,引用父组件中的值的工作。
    6. 为了当父组件修改了输入值,也要更新子组件中的 currentVal 的功能,我们需要用到 watch 属性。 watch 属性用于监听某个 prop 或者 data,当它们发生变化时,会触发定义在 watch 中的函数。这里我们监听了 currentVal 与 value,监听了 currentVal 是为了将来当内部更新了 currentVal 的场景时,可以同步到 Value,这里起核心作用的是监听 value 值。为了让输入的值在限定范围内,这里封装了一个 update() 函数。
    7. watch 中的监听函数,有两个入参,第一个是新值,第二个是旧值。这里只用到新值。因为监听函数中的 this ,指向的是当前组件实例,所以可以直接调用定义在 methods 中的函数。
    8. 为了在组件初始化时,对初始值进行范围限定,这里在 mounted 挂载函数中,也调用了 update() 函数。

    效果:

    2 按键支持

    当输入框获得焦点时,按下“向上键”时,增长;按下“向上键”时,减少。

    这可以利用按键修饰符来实现,我们修改示例中的组件模板:

    ...
     <input 
                type="text"
                :value="currentVal"
                @change="change"
                @keyup.up="up"
                @keyup.down="down">
    ...
    

    Vue.js 定义按键别名有这些:

    • .enter
    • .tab
    • .delete(捕获“删除”和“退格”键)
    • .esc
    • .space
    • .up
    • .down
    • .left
    • .right

    效果:

    3 控制步伐

    新增一个步伐属性,增长或者减少以步伐值为变化量。之前的示例,步伐为 1。

    首先在 props 中,定义一个步伐属性:

    //步伐
    step: {
        type: Number,
        default: 1
    }
    

    然后在增长与减少函数中,使用步伐属性做为变化量:

    /**
     * 减少
     */
    down: function () {
        if (this.currentVal <= this.min) {
            return;
        }
        this.currentVal -= this.step;
    },
    /**
     * 增长
     */
    up: function () {
        if (this.currentVal >= this.max) {
            return;
        }
        this.currentVal += this.step;
    },
    

    最后为组件重新配置参数:

    <number-input v-model="value" :min="0" :max="50" :step="5"></number-input>
    

    效果:

    本文示例代码

    相关文章

      网友评论

        本文标题:说说如何在 Vue.js 中实现数字输入组件

        本文链接:https://www.haomeiwen.com/subject/jfvvlqtx.html