目录
  1. 1. 父子组件通信
  2. 2. Vue2+
    1. 2.1. v-model 的本质
    2. 2.2. v-model 双向绑定
    3. 2.3. .sync 的本质
    4. 2.4. .sync 双向绑定
  3. 3. Vue3 中的变化
    1. 3.1. v-model
    2. 3.2. 利用 computed 实现双向绑定
    3. 3.3. 绑定多个 v-model
  4. 4. 总结
Vue组件双向绑定v-model与.sync修饰符,以及Vue3中的变化【前端随笔】
Note-Vue

父子组件通信

父组件自定义方法接收数据;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
<!-- 调用子组件 -->
<my-input :value="val" @changeVal="handleChangeVal">
</template>

<script>
export default {
data() {
return {
val: ''
}
},
methods: {
handleChangeVal(val) {
this.val = val
}
}
}
</script>

MyInput 子组件 emit 自定义事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<template>
<input type="text" :value="value" @input="handleInput">
</template>

<script>
export default {
props: {
value: [String, Number]
},
emits: ['changeVal']
methods: {
handleInput(event) {
this.$emit('changeVal', event.target.value)
}
}
}
</script>

以上通过父子组件通信的方式一样能双向绑定数据,但需要通过父组件自定义事件接收数据,能不能像表单一样通过 v-model 来实现自定义组件的双向绑定呢?


Vue2+

v-model 的本质

1
<input type="text" v-model="myValue" />

本质上等价于

1
<input type="text" :value="myValue" @input="myValue = $event.target.value" />

而当使用在一个组件上时,v-model 会被展开为如下的形式:

1
<my-input :value="myValue" @input="myValue = $event"/>

v-model 双向绑定

默认情况下,一个组件上的 v-model 默认会利用名为 valueprop 和名为 input 的事件。

MyInput组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<template>
<input type="text" :value="value" @input="handleInput">
</template>

<script>
export default {
props: {
value: [String, Number]
},
methods: {
handleInput(event) {
this.$emit('input', event.target.value)
}
}
}
</script>

调用 MyInput 组件

1
<my-input v-model="myValue" />

以上即可通过 v-model 实现双向绑定,但是像单选框、复选框等类型的输入控件可能会将 value attribute 用于不同的目的。model 选项可以用来避免这样的冲突:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
<input
type="checkbox"
:checked="checked"
@change="$emit('change', $event.target.checked)"
>
</template>

<script>
export default {
model: {
prop: 'checked',
event: 'change'
},
props: {
checked: Boolean
}
}
</script>

现在在这个组件上使用 v-model 的时候:

1
<my-input v-model="val"/>

这里的 val 的值将会传入这个名为 checkedprop。同时当 MyInput 组件触发一个 change 事件并附带一个新的值的时候,这个 val 的 property 将会被更新。


.sync 的本质

1
<my-component :title.sync="title" />

等价于

1
<my-component :title="title" @update:title="title = $event" />

注意带有 .sync 修饰符的 v-bind 不能和表达式一起使用 (例如 v-bind:title.sync=”title + ‘!’” 是无效的)。取而代之的是,你只能提供你想要绑定的 property 名,类似 v-model


.sync 双向绑定

MyDialog 组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
<div v-show="show">
<slot></slot>
<button @click="handleClose">关闭</button>
</div>
</template>

<script>
export default {
props: {
show: Boolean
},
methods: {
handleClose() {
this.$emit('update:show', false)
}
}
}
</script>

调用 MyDialog 组件

1
2
3
<my-dialog :show.sync="dialogShow">
<div>......</div>
</my-dialog>

Vue3 中的变化

Vue3 迁移指南 - v-model

  • 用于自定义组件时,v-model prop 和事件默认名称已更改:
    • prop:value -> modelValue
    • 事件:input -> update:modelValue
  • v-bind.sync 修饰符和组件的 model 选项已移除,可在 v-model 上加一个参数代替;
  • 现在可以在同一个组件上使用多个 v-model 绑定;

v-model

Vue3 中 v-model 使用在组件中不再是默认利用名为 value 的 prop 和名为 input 的事件了。当使用在一个组件上时,v-model 会被展开为如下的形式:

1
2
3
4
5
6
<my-input v-model="myValue">
<!-- 等价于 -->
<my-input
:modelValue="myValue"
@update:modelValue="newValue => myValue = newValue"
/>

<my-input> 组件内部需要做两件事:

  1. 将内部原生 <input> 元素的 value attribute 绑定到 modelValue prop
  2. 当原生的 input 事件触发时,触发一个携带了新值的 update:modelValue 自定义事件
1
2
3
4
5
6
7
8
9
10
11
12
<!-- MyInput.vue -->
<script setup>
defineProps(['modelValue'])
defineEmits(['update:modelValue'])
</script>

<template>
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
/>
</template>

利用 computed 实现双向绑定

在组件内实现 v-model 的方式是使用一个可写的,同时具有 gettersettercomputed 属性。get 方法需返回 modelValue prop,而 set 方法需触发相应的事件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!-- MyInput.vue -->
<script setup>
import { computed } from 'vue'

const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])

const value = computed({
get() {
return props.modelValue
},
set(value) {
emit('update:modelValue', value)
}
})
</script>

<template>
<input v-model="value" />
</template>

绑定多个 v-model

1
2
3
4
5
6
7
8
9
10
<ChildComponent v-model:title="pageTitle" v-model:content="pageContent" />

<!-- 等价于 -->

<ChildComponent
:title="pageTitle"
@update:title="pageTitle = $event"
:content="pageContent"
@update:content="pageContent = $event"
/>

总结

自定义组件的双向绑定,本质上都是通过父子组件双向通信的方式,只是 v-model.sync 修饰符提供了简写方式的语法糖,可以不用父组件提供接收参数事件。

Vue2:

  • 使用 v-model ,默认绑定 value prop值和 input 事件,可通过 model 属性改变默认绑定prop和事件,但只能绑定单一 prop 值;
  • 使用 v-bind.sync 修饰符,可绑定多个 prop 值,使用 update:myPropName 事件;

Vue3:

  • 废除了 model 属性、.sync 修饰符;
  • v-model 默认绑定 modelValue prop值和 update:modelValue 事件;
  • v-model 可通过 v-model:myPropName 绑定多个 prop 值;

文章作者: Vincent F0ng
文章链接: https://vincef0ng.cn/post/two-way-binding-in-vue2-and-vue3/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Vincent F0ng
请喝奶茶
  • 微信
  • 支付宝
领红包

评论(支持Markdown)