本文只是看了官方文档和相关资料之后做的笔记:官方文档
<input v-model="something">
是下面两条语句的语法糖:
<input
v-bind:value="something" // 绑定value的初始值
v-on:input="something = $event.target.value"> // input事件发生时,something的值和该input框的value同步
如果是在组件中使用,不能之间用v-model
,因为子组件不能改变props
中的变量。
所以就拆成两步:
- 将
input
框的value
的初始值和something
绑定。 - 当
input
框中的值改变时,触发父实例中的input
事件,让该事件的回调函数改变something
的值。
1. 文本框
<body>
<div id="app1">
<p>price: {{ price }}</p>
<!-- v-model的作用是该组件发生input事件时,同步更新绑定的price -->
<!-- 也就是说要通过手动触发该组件的input事件来达到更新price的目的 -->
<currency-input v-model="price"></currency-input>
</div>
<script>
Vue.component('currency-input', {
// input事件绑定了updateValue函数
template: '\
<span>\
$\
<input\
ref="input"\
v-bind:value="value"\
v-on:input="updateValue($event.target.value)"\
>\
</span>\
',
props: ['value'],
methods: {
// 将value格式化之后,触发父实例的input事件,并传出value值
updateValue: function (value) {
var formattedValue = value
// 删除两侧的空格符
.trim()
// 保留 2 位小数
.slice(
0,
value.indexOf('.') === -1 ?
value.length :
value.indexOf('.') + 3
)
// 如果值尚不合规,则手动覆盖为合规的值
if (formattedValue !== value) {
this.$refs.input.value = formattedValue
}
// 通过 input 事件带出数值
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,当这个event发生时,改变这个prop的值,这里的“waffle”绑定的是v-model绑定的值
model: {
prop: 'waffle',
event: 'change',
},
template: '#radio-template',
props: {
value: { // 单选框的值
type: [String, Number],
},
waffle: { // 上面model中声明的prop
default: '',
},
label: { // 标签
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. 复选框
复选框有单复选框,多复选框两种。单复选框绑定一个Boolean
,多复选框绑定一个数组。
<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,当这个event发生时,改变这个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]; // 复制waffle数组
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
数组“展开”,并把元素都复制到newValue
中。为什么不直接let newValue = this.waffle
呢?因为直接赋值会让newValue
和 waffle
指向同一个数组,这时改变newValue 也就是改变 waffle。Vue不会报错!但是我们都知道最好不要在子组件中改变父组件的值。
温馨提示:
文中的代码只是演示作用,在实际运用时用slot
代替{{ label }}
更加科学。并且input
还有许多可能用到的属性,比如disabled
、name
等等,如果你需要用到这些属性,需要将它们声明在props
中并传入input
标签,用法和本文代码中的checked
、value
是一样的。
网友评论