vue2 与 vue3 实现自定义组件v-model双向数据绑定的方式

46 篇文章 1 订阅
17 篇文章 0 订阅

前言

有时候我们需要对一个组件绑定自定义 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>
  • 9
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值