前言
有时候我们需要对一个组件绑定自定义 v-model,以更方便地实现双向数据
甚至有时候,我们想要实现绑定多个 “v-model”,也就是多个“双向绑定”,好在 vue 3 已经实现了可使用多个 v-model
例如:
自定义表单输入控件
弹窗封装组件,控制展示与隐藏
vue2
单个“双向绑定”的实现
其实 v-model 本质就是 value + change 的语法糖,监听传入内容并触发改变,因此只要实现 “监听” + “触发” 就可以实现自定义 v-model
<!-- 父组件 -->
<template>
<Child v-model="parentValue" />
</template>
<script>
import Child from './components/child.vue'
export default {
name: 'ParentComponent',
components: {
Child,
},
data() {
return {
parentValue: '', // 父组件数据
}
},
}
</script>
<style scoped lang="scss"></style>
<!-- 子组件 -->
<template>
<input v-model="getValue" />
</template>
<script>
export default {
name: 'ChildComponent',
props: {
childValue: String,
},
model: {
prop: 'childValue', // 指定 v-model 要绑定的参数叫什么名字,来自于 props 中定义的参数
event: 'updateValue', // 指定要触发的事件名字,将被用于 $emit
},
computed: {
getValue: {
// 这里的计算属性使用了 getter、setter,可以简化代码
// 可参见链接 https://cn.vuejs.org/v2/guide/computed.html#%E8%AE%A1%E7%AE%97%E5%B1%9E%E6%80%A7%E7%9A%84-setter
get() {
return this.childValue
},
set(val) {
this.$emit('updateValue', val) // 触发
},
},
},
}
</script>
<style scoped lang="scss"></style>
通过这样的方式,我们就实现了自定义组件的 v-model,重点在于子组件中 model 的声明和 emit 事件
vue3
vue2 中的 v-model 和 .sync 功能重叠,容易混淆,因此 vue3 做了统一,一个组件可以多次使用 v-model
注意:
vue3 移除了 model 选项,就是上面示例 vue2 中的用法
model: {
prop: '', // 指定 v-model 要绑定的参数叫什么名字,来自于 props 中定义的参数
event: '', // 指定要触发的事件名字,将被用于 $emit
}
单个数据双向绑定
<!-- 父组件 -->
<template>
<Child v-model="parentValue" />
</template>
<script setup name='ParentComponent' lang="ts">
import Child from './components/child.vue'
import { ref } from 'vue';
const parentValue = ref('')
</script>
<style scoped lang="scss"></style>
<!-- 子组件 -->
<template>
<input v-model="getValue" />
</template>
<script setup name='ChildComponent' lang="ts">
import { ref, computed, defineEmits, defineProps } from 'vue'
const props = defineProps({
modelValue: {
type: String,
default: '',
},
})
const emit = defineEmits(['update:modelValue'])
const getValue = computed({
get() {
return props.modelValue
},
set(newValue) {
emit('update:modelValue', newValue)
},
})
</script>
<style scoped lang="scss"></style>
vue3 使用特定的 modelValue ,避免 value 的占用,通过 update:modelValue 实现数据双向绑定
多个数据双向绑定
<!-- 父组件 -->
<template>
<Child v-model:name="parentName" v-model:age="parentAge" />
</template>
<script setup name='ParentComponent' lang="ts">
import Child from './components/child.vue'
import { ref } from 'vue'
const parentName = ref('')
const parentAge = ref('')
</script>
<style scoped lang="scss"></style>
<!-- 子组件 -->
<template>
<input v-model="getNameValue" />
<input v-model="getAgeValue" />
</template>
<script setup name='ChildComponent' lang="ts">
import { ref, computed, defineEmits, defineProps } from 'vue'
const props = defineProps({
name: {
type: String,
default: '',
},
age: {
type: String,
default: '',
},
})
const emit = defineEmits(['update:name','update:age'])
const getNameValue = computed({
get() {
return props.name
},
set(newValue) {
emit('update:name', newValue)
},
})
const getAgeValue = computed({
get() {
return props.age
},
set(newValue) {
emit('update:age', newValue)
},
})
</script>
<style scoped lang="scss"></style>