亲自动手实现一个v-model
大家好,我是铁柱,时常分享一些项目的收获。 点赞 + 关注 + 收藏 = 学会了
新增:vue3 v-model已更新(2022-12-30)
背景
在日常封装组件时,会遇到这种情况,给子组件传值,然后经过子组件的内部处理,将处理之后的值再传回父组件,平常会使用父子组件之间的相互传值实现,父组件传入属性,子组件通过 props
接收,子组件通过$emit()
向外弹出一个自定义事件, 在父组件中的属性监听事件,同时也能获取子组件传出来的参数,这样写既要在父组件中处理属性还需要处理自定义事件的回调,今天就给大家介绍一下使用 v-model
是如何处理这种情况的。
一个好的公共组件,首先是 API
的设计应该让人容易理解,并且使用方便。再就是应该尽量将公共逻辑放在子组件中,这样子才会让组件的封装更有意义。
基础知识-父子组件的通信,父子组件之间怎么传值
子组件:
<template>
<div>
父组件传递的数据{{ parentText }}
<button @click="$emit('childEvent', '子组件的数据')">按钮</button>
</div>
</template>
<script>
export default {
name: 'ChildCompontent',
props: {
// 接收父组件的数据
parentText: String,
},
}
</script>
父组件:
<template>
子组件传递的数据{{ childText }}
<child-compontent parentText="父组件的数据" @childEvent="parentFn" />
</template>
<script>
import ChildCompontent from './components/ChildCompontent'
export default {
components: { ChildCompontent },
data() {
return {
childText: ''
}
},
methods: {
parentFn(val) {
// 接收子组件的数据
this.childText = val
}
}
}
</script>
vue2使用v-model改造父子组件的通信
子组件:
<template>
<div>
父组件传递的数据{{ this.$attrs.parentText }}
<button @click="$emit('childEvent', '子组件的数据')">按钮</button>
</div>
</template>
<script>
export default {
name: 'ChildCompontent',
model: {
event: 'childEvent', // 默认值input
prop:'parentText' // 默认值value
},
}
</script>
父组件:
<template>
text的数据{{ text }}
<child-compontent v-model="text" />
</template>
<script>
import ChildCompontent from './components/ChildCompontent'
export default {
components: { ChildCompontent },
data() {
return {
// 接收子组件的数据
text: '父组件的数据'
}
},
}
</script>
(新)vue2和vue3中v-model两者的区别
-
默认值的改变
- prop:value -> modelValue
- 事件:input -> update:modelValue
-
新增 支持多个v-model
-
新增 支持自定义 修饰符 Modifiers
-
v-bind 的 .sync 修饰符和组件的 model 选项已移除
(新)vue3使用v-model改造父子组件的通信
子组件:
<template>
<div>
父组件传递的数据{{ modelValue }}
<button @click="$emit('update:modelValue', '子组件的数据')">按钮</button>
<button @click="$emit('update:text2', '子组件的数据text2')">按钮text2</button>
</div>
</template>
<script setup>
defineProps({ modelValue: String, text2: String, })
defineEmits(['update:modelValue', 'update:text2'])
</script>
父组件:
<template>
text的数据{{ text }}
text2的数据{{ text2 }}
<child-compontent v-model="text" v-model:text2="text2" />
</template>
<script setup>
import ChildCompontent from './components/ChildCompontent'
let text = ref('父组件的数据')
let text2 = ref('')
</script>
小结
通过比较,这样处理之后在使用组件时,无需记特定的 prop
字段名,即可绑定到组件中的值,也无需处理自定义事件,降低组件的使用成本。
v-model
实际上就是 $emit('input')
以及 props:value
的组合语法糖,只要组件中满足这两个条件,就可以在组件中使用 v-model
。
凡事都有例外,例如:
checkbox
和 radio
使用 props:checked
属性和 $emit('change')
事件。
select
使用 props:value
属性和 $emit('change')
事件。
但是,除了上面列举的这些,别的都是 $emit('input')
以及 props:value
。