Vue.js入门 0x8 组件(Component)(5)Demo——数字输入框

    数字输入框只能输入数字,而且有两个快捷按钮,可以直接减1或加 1 。除此之外,还可以设置初始值、最大值、最小值,在数值改变时,触发一个自定义事件来通知父组件。

    首先,在写代码前一定要明确需求,然后规划好API。一个Vue组件的API只来自props、events和slots,确定好这3部分的命名、规则,剩下的逻辑即使第一版没有做好,后续也可以迭代完善。但是API如果没有设计好,后续再改对使用者成本就很大了。

     index.html 入口页

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>数字输入框组件</title>
    </head>
    <body>
        <div id="app">
            <!--在父组件引入input-number,并给他一个默认值5,最大值10,最小值0-->
            <input-number v-model="value" :max="10" :min="0"></input-number>
            <!--value是个关键的绑定值故用了v-model这样既实现了双向绑定也让API看起来很合理。-->
        </div>
        <script src="https://cdn.jsdelivr.net/npm/vue"></script>
        <script src="input-number.js"></script>
        <script src="index.js"></script>
    </body>
</html>

     input-number.js 数字输入框组件

function isValueNumber(value){
    return (/(^-?[0-9]+\.{1}\d+$)|(^-?[1-9][0-9]*$)|(^-?0{1}$)/).test(value+'');
}
Vue.component('input-number',{
    //定义组件根节点
    template:'\
        <div class="input-number">\
            <input\
                type="text"\
                :value="currentValue"\
                @change="handleChange">\
            <button \
                @click="handleDown"\
                :disabled="currentValue<=min">-</button> \
            <button \
                @click="handleUp"\
                :disabled="currentValue>=max">+</button> \
        </div>',
    props:{
        max:{
            type:Number,
            default:Infinity
        },
        min:{
            type:Number,
            default:-Infinity
        },
        value:{
            type:Number,
            default:0
        }
    },
    /**
     * Vue组件是单向数据流,所以无法从组件内部直接修改prop value 的值 。
     * 解决办法也介绍过,就是给组件声明一个data,默认引用value的值,然后
     * 在组件内部维护这个 data
     */
    data:function(){
        return {
            currentValue:this.value
        }
    },
    /**
     * watch 选项用来监昕某个 prop 或 data 的改变 , 当它们发生变化时,
     * 就会触发 watch 配置的函数,从而完成我们的业务逻辑
     */
    watch:{
        //监昕 currentValue 是为了当 currentValue 改变时,更新 value 。
        currentValue:function(val){
            //使用 v-model 时 改变 value
            this.$emit('input',val);
            //触发自定义事件 on-change ,用于告知父组件数字输入框的值有所改变
            this.$emit('on-change',val);
        },
        //监听 value 是要知晓从父组件修改了 value
        value:function(val){
            /**
             * this是指向当前组件实例的,所以可以直接调用this.updateValue(),
             * 因为 Vue 代理了 props 、 data 、 computed 及 methods
             */
            this.updateValue(val);
        }
    },
    methods:{
        /**
         * 从父组件传递过来的 value 有可能是不符合当前条件的 (大于max, 
         * 或小于 min),所以在选项 methods 里写了一个方法 updateValue ,
         *  用来过滤出一个正确的 currentValue 。
         */
        updateValue:function(val){
            if(val>this.max) val = this.max;
            if(val<this.min) val = this.min;
            this.currentValue = val;
        },
        handleDown:function(){
            if(this.currentValue<=this.min) return;
            this.currentValue -= 1;
        },
        handleUp:function(){
            if(this.currentValue>=this.max) return;
            this.currentValue +=1;
        },
        handleChange:function(event){
            var val = event.target.value.trim();
            var max = this.max;
            var min = this.min;

            if(isValueNumber(val)){
                val = Number(val);
                this.currentValue = val;

                if(val>max){
                    this.currentValue = max;
                }else if(val<min){
                    this.currentValue = min;
                }
            }else{
                event.target.value = this.currentValue;
            }
        }
    },
    /**
     * 在生命周期 mounted钩子里也调用了 updateValue()方法 ,是因为
     * 第一次初始化时 , 也对 value 进行了过滤
     */
    mounted:function(){
        this.updateValue(this.value)
    }

})

    index. 根实例

var app = new Vue({
    el:'#app',
    data:{
        value:5
    }
});

Vue.js入门 0x8 组件(Component)(5)Demo——数字输入框