Vue.js输入框组件开发

2019-03-04  本文已影响0人  咸鱼前端

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>数字输入框组件——实战</title>
    <style>
        [v-cloak]{
            display: none;
        }
        .step{
            width: 70px!important;
        }
    </style>
    <link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.min.css">
</head>
<body>
    <div id="app" v-cloak>
        <input-number v-model="value" :max="40" :min="0" :step-max='10' @on-change="updateValue"></input-number>
    </div>
    <script type="text/javascript" src="/node_modules/vue/dist/vue.js"></script>
    <script type="text/javascript" src="js/input-number.js"></script>
    <script type="text/javascript" src="js/index.js"></script>
</body>
</html>

JS

input-number.js

Vue.component("input-number", {
    template: `
    <div class="container">
        <div class="row">
            <form class="form form-inline">
                <input class='form-control' type='number' :value='currentValue' @change='handlerChange' @input='handlerChange'>
                <input class='form-control step' type='number' :value='currentStep' @input='changeStep'>
                <button class='btn btn-primary' type='button' @click='reduce' :disabled='currentValue<=min'>-</button>
                <button class='btn btn-primary' type='button' @click='crease' :disabled='currentValue>=max'>+</button>
            </form>
        </div>
    </div>
    `,
    props: {
        max: {
            type: Number,
            default:Infinity
        },
        min:{
            type:Number,
            default:-Infinity
        },
        stepMax: {
            type: Number,
            default:Infinity
        },
        stepMin:{
            type:Number,
            default:1
        },
        value:{
            type:Number,
            default:0
        },
        step:{
            type:Number,
            default:1
        }
    },
    data (){
        return {
            currentValue: this.value,
            currentStep: this.step,
        }
    },
    watch:{
        currentValue(val){
            this.updateValue(val);
            this.$emit("input",val);
            this.$emit("on-change",val)
        },
        currentStep(val){
            this.$emit("input",val);
        }
    },
    methods:{
        crease: function(){
            if(this.currentValue>=this.max) return;
            var step = this.currentStep;
            this.currentValue+=step;
        },
        reduce:function(){
            if(this.currentValue<=this.min) return;
            var step = this.currentStep;
            this.currentValue-=step;
        },
        handlerChange:function(event){
            var val = event.target.value.trim();
            if(val){
                val = Number(val);
                this.currentValue = val;
                this.updateValue(val);
            }else{
                event.target.value = this.currentValue;
            }
        },
        updateValue:function(val){
            console.log(typeof(val));
            if(val>this.max) val = this.max;
            if(val<this.min) val = this.min;
            this.currentValue = val;
        },
        updateStep:function(val){
            if(val>this.stepMax) val = this.stepMax;
            if(val<this.stepMin) val = this.stepMin;
            this.currentStep = val;
        },
        changeStep:function(event){
            var val = event.target.value.trim();
            if(val){
                val = Number(val);
                this.currentStep = val;
                this.updateStep(val);
            }else{
                event.target.value = this.currentStep;
            }
        },
    },
    mounted(){
        this.updateValue(this.value);
        this.updateStep(this.step);
    }
})

index.js

var vm = new Vue({
    el: "#app",
    data: {
        value: 20,
        step: 1
    },
    methods: {
        updateValue: function(val) {
            this.value = val;
        }
    }
})
上一篇下一篇

猜你喜欢

热点阅读