1. 程式人生 > >Vue 元件實現表單的雙向繫結

Vue 元件實現表單的雙向繫結

下面是一個簡單的貨幣輸入的自定義控制元件,來自https://cn.vuejs.org/v2/guide/components.html:

<body>
<div id="currency-input">
    <p>{{price}}</p>
    <currency-input v-model="price"></currency-input>
</div>
</body>
<script>
    Vue.component('currency-input',{
        template: '' +
        '<span>' +
        '$ <input ref="input" :value="value" @input="updateValue($event.target.value)">' +
        '</span>',
        props: ['value'],
        methods: {
            updateValue: function (value) {
                //去除空格,保留兩位小數
                var formattedValue = value.trim().slice(0,value.indexOf('.') === -1 ? value.length : value.indexOf('.')+3);
                if(formattedValue !== value){
                    this.$refs.input.value = formattedValue;
                }
                this.$emit('input', Number(formattedValue))
            }
        }
    });
    new Vue({
        el: "#currency-input",
        data: {
            price: 0
        }
    })

關於這段程式碼,看的時候有一些疑問,把自己的理解記錄下來,有可能不準確,以後如果有新的理解再來更新

1、<currency-input v-model="price"></currency-input>v-model是用在<input>中的,元件中為什麼要用v-model?

元件 currency-input 實現的是輸入框元件,元件也可以依靠 v-model 實現雙向繫結。

2、this.$emit('input', Number(formattedValue))有什麼作用,為什麼改變輸入框文字後還要特地用 $emit 觸發 input 事件?

這是元件和<input>不同的地方,元件中為了使 v-model 生效,必須滿足兩個條件:接受一個 value 屬性

以及在有新的值時觸發 input 事件

這是因為<inputv-model="something">是以下程式碼的語法糖:

<input v-bind:value="something" v-on:input="something = $event.target.value">

3、模板中<input :value="value" >為什麼用 v-bind:value 不用 v-model?

v-model 與v-bind:value 的區別在於雙向資料繫結,<input> 中的 value 屬性來自父元件的傳值,而 Vue.js 規定元件的資料傳遞prop是單向的,子元件<input>不應該在內部改變prop。這裡如果使用了v-model,Vue會給如如下警告:

vue.js:482 [Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "value"

這段文字解釋的很清楚:(子元件內)不允許直接改變prop,因為父元件重新渲染的時候,prop的值會被覆蓋。如果需要改變prop,可以基於prop的值,使用data或者computed屬性。