怎么理解
对于普通的input标签来说,大概就这样的原理
<input v-model="value">
// 其实等于
<input :value="value" @input="value = $event.target.value">
这些都是vue底层在生成render函数的时候做好的事情,例如select会对应的去调整为value与change事件;checkbox也会去调整为checked与为change事件
自定义组件中改写v-model
什么情况下需要自己改写v-model的逻辑呢?
- 基本的v-model已经不能满足我们的业务需求了
- 用最普通的传值形式太麻了
咱们看用最普通的传值形式有多麻烦
普通传值形式的缺陷
vue2举例,通过prop和emit传值去做双向变化的效果。
子组件
<template>
<input :value="value" @input="$emit('input', $event.target.value)" />
</template>
<script>
export default {
props: {
value: String
},
};
</script>
父级使用:
<my-component :value="val" @input="val = arguments[0]"> // 通过arguments默认入参集合去接收
可以看到不仅麻烦,还有其他问题:
- 可读性比较差,别人要通过看你组件的代码才能理解到
:value
是个双向绑定。 - 当绑定值是个对象时,这种方法满足不了。
vue2改写方法
<!-- 基础输入框 -->
<template>
<el-input v-model="input"></el-input>
</template>
<script>
export default ({
name: 'PzInput',
model: {
prop: 'inputProp', // 表明v-model传进来的变量,由props的指定变量接收
event: 'input' // 表明子组件可以通过input这个方法可修改外部v-model变量,这样就可实现双向修改绑定
},
props: {
// 外层v-model的接收
inputProp: {
type: String,
default: ''
}
},
data() {
return {
input: ''
}
}
watch: {
// 把选择的结果暴露出v-model
input: {
handler() {
this.$emit('input', this.input) // 暴露出v-model
}
},
// 监听外部v-model传进来的
inputProp: {
handler(val) {
this.input = val // 如果表单点了重置按钮
},
immediate: true
}
}
})
</script>
看到没,其实原理就是:
- 告诉vue,重新指定了值和修改事件
- 再监听输入的值并更新内部的最新值,以及抛出修改的最新值
如果是要双向绑定对象,那我再举个表单组件的例子:
// 组件中
model: {
prop: 'formData', // 表明v-model.trim传进来的变量,由props的指定变量接收
event: 'input'
},
props: {
formData: { // 传入已有数据
type: Object,
default() {
return {}
}
},
},
data() {
return {
form: {}
}
},
watch: {
// 把选择的结果暴露出v-model.trim
form: {
handler() {
this.$emit('input', this.form) // 暴露出v-model.trim
},
deep: true
},
// 监听外部v-model.trim传进来的,填入到data中的form,这样可以防止数据是异步获取从而获取不到的问题
formData: {
handler() {
this.form = this.formData
},
immediate: true,
deep: true
},
}
父组件:
<my-component v-model="formData"></my-component >
虽然子组件代码量多了,但是父组件的可读性是比较好的。
vue3改写方法
这里偷个懒嘻嘻~
看文档里那个【多个 v-model 绑定】的方法就行了,等我以后有实践了再来补充。
附上文档链接:https://cn.vuejs.org/guide/components/v-model.html#multiple-v-model-bindings