前言
有时候我们需要对一个组件绑定自定义 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-setterget() {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>