一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第19天,点击查看活动详情。
在vue2中的双向绑定使用 v-model, 但是存在一些问题, 比如哲学问题吧哈哈。
vue2中的v-model存在哪些问题
哲学问题
在vue2想要进行双向绑定可以使用v-model既可以到达双向绑定的目的, 又可以少书写代码。(v-model)本质是一个语法糖至于实现原理我相信大家都懂。
<template >
<div class="test">
<input type="text" v-model="value">
</div>
</template>
<script>
export default {
data() {
return {
value:''
}
}
}
</script>
这是vue2中常见的写法, 但是在使用一些UI库时会发现有写地方可能会用到sync修饰符,sync的作用也是做双向绑定, 一般用在子组件可以修改父组件的值,父组件为了图方便就可以使用sync修饰符, 所以sync本质上是一个语法糖, 它的实现原理如下:
// 子组件
<template >
<div class="test-sync-container">
<input type="text" :value="value" @input="handleValue">
</div>
</template>
<script>
export default {
props: ['value'],
methods: {
handleValue(event) {
this.$emit('update:value', event.target.value)
}
},
}
</script>
// 父组件
<template >
<div class="test">
<TestSync :value="value" @update:value="value = $event"/>
</div>
</template>
<script>
import TestSync from "./components/TestSync.vue";
export default {
data() {
return {
value: ''
}
},
components: {
TestSync
}
}
</script>
在父组件中的写法就可以简写为 :value.sync="value"
就可以省略手动书写一个函数。
这里其实就存在一个哲学问题, 既然v-model、sync都是做双向绑定的,那为什么做出两个语法糖?
尤大大在vue3中就删除了sync只保留了v-model
在vue3中怎么统一使用v-model实现双向绑定?
vue3中v-model的语法更新
在vue3对v-model做了不兼容的更新(具体如下)
-
非兼容:用于自定义组件时,
v-model
prop 和事件默认名称已更改:- prop:
value
->modelValue
; - 事件:
input
->update:modelValue
;
- prop:
-
非兼容:
v-bind
的.sync
修饰符和组件的model
选项已移除,可在v-model
上加一个参数代替; -
新增:现在可以在同一个组件上使用多个
v-model
绑定; -
新增:现在可以自定义
v-model
修饰符。
非兼容:用于自定义组件时,v-model
prop 和事件默认名称已更改:
解释下:在自定义组件中v-model不在是绑定value属性, 而是modelValue属性, 触发的事件由input事件改为update:modelValue(注意这都是默认情况下)
用代码解释更清楚
// 子组件
<template >
<div class="test-sync-container">
<input type="text" :value="modelValue" @input="handleValue">
</div>
</template>
<script>
export default {
props: ['modelValue'], // 默认是这个属性 modelValue
setup(props, ctx) {
const handleValue = (event) => {
// 默认事件名 update:modelValue
ctx.emit('update:modelValue', event.target.value)
}
return {
handleValue
}
}
}
</script>
// 父组件
<template >
<div class="test">
<TestSync v-model="value"/>
</div>
</template>
<script>
import TestSync from "./components/TestSync.vue";
export default {
data() {
return {
value: ''
}
},
components: {
TestSync
}
}
</script>
这是默认情况, 如果相对某些值使用双向绑定可以这样写 v-model:属性名="属性值" 触发的事件改为 update:属性名
// 子组件
<template >
<div class="test-sync-container">
<input type="text" :value="test" @input="handleTest">
</div>
</template>
<script>
export default {
props: ['test'],
setup(props, ctx) {
const handleTest = (event) => {
// 事件名
ctx.emit('update:test', event.target.value)
}
return {
handleTest
}
}
}
</script>
// 父组件
<template >
<div class="test">
<TestSync v-model:test="value"/>
</div>
</template>
<script>
import TestSync from "./components/TestSync.vue";
export default {
data() {
return {
value: ''
}
},
components: {
TestSync
}
}
</script>
vue3规范了v-model的写法使得更加的简介明了。
自定义 v-model
修饰符
vue3中可以对v-model增加自定的修饰符, 自定义修饰符通过props.modelModifiers(默认属性 modelValue), props.属性名Modifiers (自定义属性)
默认情况 v-model.abc="value"
modelModifiers = {
abc:true
}
自定义属性 v-model:test.time="value"
testModifiers = {
trim:true
}
对每一个双向绑定的属性都添加了一个 修饰符对象
总结
在 Vue 3 中,双向数据绑定的 API 已经标准化,以减少开发者在使用 v-model
指令时的混淆,并且更加灵活。