场景
总结一波 v-model 原理,先说结论:v-model 本身是 v-bind 和 v-on 结合在一起的语法糖,是用于原生标签(如input、textarea...
)和自定义组件上的一个简化包装,在 vue2 中 props 接收的 value,事件为 $emit(事件);在 vue3 中接收的 modelValue,事件为 $emit('update:modelValue')。原生的 v-model 会自动识别标签属性和事件。下面说实现。
步骤
以下代码实现全部是在工程化 vue3 中实现,但在 vue3 中也是支持 vue2 写法的,只不过会有坑
- 实现一个基本的语法糖
// index.vue
<template>
<div class="test-vc">
<input
:value="vc"
type="text"
placeholder="请输入内容"
@input="vc = $event.target.value"
/>
<div> 输入的文本内容:{{ vc }} </div>
</div>
</template>
<script>
export default {
name: 'Test',
data() {
return {
vc: ''
};
}
};
</script>
<style>
.test-vc {
width: 200px;
height: 200px;
padding: 16px;
margin: 20px auto 0;
border: 1px solid #ddd;
border-radius: 4px;
}
</style>
- 完结版-在子组件上实现双向绑定(vue3 && vue2)
// 子组件代码
<template>
<div class="test-child">
子组件
<input type="text" placeholder="请输入内容" @input="onInput" />
子组件输入内容:{{ modelValue }}
</div>
</template>
<script>
export default {
name: 'ChangeChild',
props: {
// 如果是 vue2 这里 modelValue 换成 value,方法内还有一处
modelValue: {
type: String,
default: ''
}
},
data() {
return {};
},
methods: {
onInput(event) {
// 如果是 vue2 这里 update:modelValue 换成 input
this.$emit('update:modelValue', event.target.value);
}
}
};
</script>
<style>
.test-child {
margin-top: 20px;
}
</style>
// 父组件代码
<template>
<div class="test-vc">
<input
:value="vc"
type="text"
placeholder="请输入内容"
@input="vc = $event.target.value"
/>
<div> 输入的文本内容:{{ vc }} </div>
<ChangeChild v-model="vd" />
</div>
</template>
<script>
import ChangeChild from './ChangeChild.vue';
export default {
name: 'Test',
components: { ChangeChild },
data() {
return {
vc: '',
vd: ''
};
}
};
</script>
<style>
.test-vc {
width: 200px;
height: 200px;
padding: 16px;
margin: 20px auto 0;
border: 1px solid #ddd;
border-radius: 4px;
}
</style>