本文只是看了官方文檔和相關(guān)資料之后做的筆記:官方文檔
?
<input v-model="something">
是下面兩條語句的語法糖:
<input
v-bind:value="something" // 綁定value的初始值
v-on:input="something = $event.target.value"> // input事件發(fā)生時,something的值和該input框的value同步
如果是在組件中使用,不能之間用v-model
,因為子組件不能改變props
中的變量。
所以就拆成兩步:
- 將
input
框的value
的初始值和something
綁定。 - 當(dāng)
input
框中的值改變時,觸發(fā)父實例中的input
事件,讓該事件的回調(diào)函數(shù)改變something
的值。
1. 文本框
<body>
<div id="app1">
<p>price: {{ price }}</p>
<!-- v-model的作用是該組件發(fā)生input事件時,同步更新綁定的price -->
<!-- 也就是說要通過手動觸發(fā)該組件的input事件來達到更新price的目的 -->
<currency-input v-model="price"></currency-input>
</div>
<script>
Vue.component('currency-input', {
// input事件綁定了updateValue函數(shù)
template: '\
<span>\
$\
<input\
ref="input"\
v-bind:value="value"\
v-on:input="updateValue($event.target.value)"\
>\
</span>\
',
props: ['value'],
methods: {
// 將value格式化之后,觸發(fā)父實例的input事件,并傳出value值
updateValue: function (value) {
var formattedValue = value
// 刪除兩側(cè)的空格符
.trim()
// 保留 2 位小數(shù)
.slice(
0,
value.indexOf('.') === -1 ?
value.length :
value.indexOf('.') + 3
)
// 如果值尚不合規(guī),則手動覆蓋為合規(guī)的值
if (formattedValue !== value) {
this.$refs.input.value = formattedValue
}
// 通過 input 事件帶出數(shù)值
this.$emit('input', Number(formattedValue))
}
}
})
var app1 = new Vue({
el: "#app1",
data: {
price: 0,
},
});
</script>
</body>
2. 單選框
<body>
<div id="app">
waffle: {{ waffle }}
<ui-radio value="aaa" v-model="waffle" name="method" label="牛奶"></ui-radio>
<ui-radio value="bbb" v-model="waffle" name="method" label="奶茶"></ui-radio>
<ui-radio value="ccc" v-model="waffle" name="method" label="可樂"></ui-radio>
</div>
<template id="radio-template">
<label>
<input type="radio" ref="radio" :value="value" :checked="shouldBeChecked" @change="updateVal"> {{ label }}
</label>
</template>
<script>
Vue.component('ui-radio', {
// 自定義v-model的prop和event,當(dāng)這個event發(fā)生時,改變這個prop的值,這里的“waffle”綁定的是v-model綁定的值
model: {
prop: 'waffle',
event: 'change',
},
template: '#radio-template',
props: {
value: { // 單選框的值
type: [String, Number],
},
waffle: { // 上面model中聲明的prop
default: '',
},
label: { // 標(biāo)簽
type: String,
require: true,
},
},
computed: {
shouldBeChecked () { // 判斷單選框是否被選中
return this.waffle == this.value
}
},
methods: {
updateVal: function () { // 通過change事件輸出value值
this.$emit('change', this.value);
}
}
});
var app = new Vue({
el: "#app",
data: {
waffle: '',
}
})
</script>
</body>
3. 復(fù)選框
復(fù)選框有單復(fù)選框,多復(fù)選框兩種。單復(fù)選框綁定一個Boolean
,多復(fù)選框綁定一個數(shù)組。
<body>
<div id="app">
waffle: {{ waffle }}
<checkbox value="aaa" v-model="waffle" label="aaa"></checkbox>
<checkbox value="bbb" v-model="waffle" label="bbb"></checkbox>
<checkbox value="ccc" v-model="waffle" label="ccc"></checkbox>
</div>
<template id="checkbox-template">
<label>
<input type="checkbox" :value="value" :checked="shouldBeChecked" @change="updateVal"> {{ label }}
</label>
</template>
<script>
Vue.component('checkbox', {
// 自定義v-model的prop和event,當(dāng)這個event發(fā)生時,改變這個prop的值
model: {
prop: 'waffle',
event: 'change',
},
template: '#checkbox-template',
props: {
value: {
type: [String, Number],
require: true,
},
waffle: {
default: false
},
checked: {
type: Boolean,
default: false
},
label: {
type: String,
require: true
},
trueValue: {
default: true
},
falseValue: {
default: false
}
},
computed: {
shouldBeChecked() {
if (this.waffle instanceof Array) {
return this.waffle.includes(this.value)
}
return this.waffle == this.trueValue
}
},
methods: {
updateVal: function (event) {
let isChecked = event.target.checked;
if (this.waffle instanceof Array) {
let newValue = [...this.waffle]; // 復(fù)制waffle數(shù)組
if (isChecked) {
newValue.push(this.value);
} else {
newValue.splice(newValue.indexOf(this.value), 1);
}
this.$emit('change', newValue);
} else {
this.$emit('change',isChecked ? this.trueValue : this.falseValue);
}
}
}
});
var app = new Vue ({
el: "#app",
data: {
waffle: [],
}
})
</script>
</body>
注意到代碼中的一句:let newValue = [...this.waffle];
,這里是把waffle
數(shù)組“展開”,并把元素都復(fù)制到newValue
中。為什么不直接let newValue = this.waffle
呢?因為直接賦值會讓newValue
和 waffle
指向同一個數(shù)組,這時改變newValue 也就是改變 waffle。Vue不會報錯!但是我們都知道最好不要在子組件中改變父組件的值。
?
溫馨提示:
文中的代碼只是演示作用,在實際運用時用slot
代替{{ label }}
更加科學(xué)。并且input
還有許多可能用到的屬性,比如disabled
、name
等等,如果你需要用到這些屬性,需要將它們聲明在props
中并傳入input
標(biāo)簽,用法和本文代碼中的checked
、value
是一樣的。