默认元素v-model:
vue 中的v-model 实现了对数据的双向绑定,即 数据->模版,模版-> 数据 的绑定, 例如:
<input type="text" v-model="message">
<p>{{message}}</p>
v-model 是经过vue封装后的一个指令,目的是方便我们使用,它内部真实的实现方式:
<input :value="message" @input="message = $event.target.value">
上面一共两个步骤:
-
将输入框的值value 绑定到message 变量上,这样改变 message 的值可以改变输入框的值,但是改变输入框的值不能改变message 的值。
-
监听输入框的input事件,当发生输入内容时,改变message变量的值,这样就实现了双向绑定。
官网上说,v-model在内部为不同的输入元素使用不同的属性并抛出不同的事件:
- text 和 textarea 使用 value 和 input事件
- checkbox 和 radio 使用 checked 和 change事件
- select 使用 value 和 change 事件
自定义组件双向绑定:
当我们知道这些后, 可以试着写自定义输入框组件的v-model:
Vue.component('default-input', {
template: '<input :value="value" @input="updateVal($event.target.value)" type="text" />',
props: ['value'],
methods: {
updateVal(val){
this.$emit('input', val)
}
}
})
// 父组件部分
var app = new Vue({
el: '#app',
data: {
price: ''
},
methods: {
onInput (val) {
this.price = val
}
}
})
// html部分
<div id="app">
<default-input :value="price" @input="onInput"/>
</div>
默认情况下,一个组件上的v-model 会把value作为 prop ,并且把input作为event。 但是自定义组件中使用v-model并不能实现双向绑定,因为自定义组件没有默认的value 和 input事件,所以在实现的时候需要我们去显式的声明这些东西。而vue2中的model就解决了这个问题,它可以在定义组件的时候去指定prop的值 和 监听的事件。
自定义组件v-model双向绑定:
Vue.component('my-input', {
// 指定v-model对应的prop值 和 event事件名称
model: {
prop: 'name',
event: 'changeName'
},
props: ['name'],
methods: {
updateVal(val){
// 抛出的事件名称 参数值默认修改prop name, 实现双向绑定
this.$emit('changeName', val)
}
}
})
// html部分
<template>
<input type="text" :value="name" @input="updateVal($event.target.value)">
</template>
父组件调用时可以直接使用v-model就可以:
<template>
// userName是父组件中的属性也可以是其他xxx
<default-input v-model="userName"/>
{{userName}}
</template>
等同于:
<default-input :name="userName" @changeName="(val) => {userName = val}"/>
vue3 中v-model:
v-model 对应的prop 和 事件名称已经修改为:modelValue 和 update:modelValue
<template>
<div @click="updateValue(value)"></div>
</template>
// 子组件内部
export default defineComponent({
name: "my-input3",
props: {
modelValue:String // 可以更改为其他属性
},
setup(props, context){
const updateValue = (e: KeyboardEvent) => {
context.emit("update:modelValue",e); // 传递的方法
}
return {
updateValue
}
}
}
// 父组件
<my-input3 v-model:modelValue="userName"/>
// 等同于
<my-input3 :modelValue="userName" @update:modelValue="userName = $event"/>
modelValue也可以更改为其他更为见明知义的属性:
// 子组件内部
export default defineComponent({
name: "my-input3",
props: {
name:String // 可以更改为其他属性
},
setup(props, context){
const updateValue = (e: KeyboardEvent) => {
context.emit("update:name",e); // 传递的方法
}
}
}
// 父组件
<my-input3 v-model:name="userName"/>
// 等同于
<my-input3 :name="userName" @update:name="userName = $event"/>
对普通prop进行双向绑定:
v-bind.sync (已废弃),使用 v-model:propName 代替
// 子组件抛出update:myPropName事件
this.$emit('update:title', newValue)
// 父级监听:
<my-input3 :title="userName" @update:title="userName = $event"/>
// 简写:
<my-input3 :title.sync="userName" />