组件的v-model
# 组件的v-model 🔥
# 推荐 🔥
- 只推荐绑定单个值!
- 绑定对象推荐自己写!
# 使用 🔥
前面我们在input中可以使用v-model来完成双向绑定,这个时候往往会非常方便,因为v-model默认帮助我们完成了两件事:
- v-bind:value的数据绑定
- @input的事件监听
<input v-model="message">
<input :value="message" @input="message = $event.target.value">
1
2
2
如果我们现在封装了一个组件,其他地方在使用这个组件时,是否也可以使用v-model来同时完成这两个功能呢? 也是可以的,vue也支持在组件上使用v-model。类似Vue2的.sync
当我们在组件上使用的时候,等价于如下的操作:
<template>
<!-- 组件上使用v-model -->
<hy-input v-model="message"></hy-input>
<!-- 等价于如下 -->
<hy-input :modelValue="message" @update:model-value="message = $event"></hy-input>
<h2>{{ message }}</h2>
</template>
<script>
import HyInput from './HyInput.vue'
export default {
components: {
HyInput,
},
data() {
return {
message: 'Hello World',
}
},
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
所以 hy-input 组件中也应该提供 modelValue prop 和 update:model-value emit
<template>
<div>
<!-- 1.默认绑定和事件处理。事件还得button触发,不优雅 -->
<!-- <button @click="btnClick">hyinput按钮</button>
<h2>HyInput的message: {{modelValue}}</h2> -->
<!-- 2.通过input,也不是很优雅 -->
<!-- <input :value="modelValue" @input="btnClick"> -->
<!-- 3.绑定到props中是不对的,单向数据流,不应该修改props中的值 -->
<!-- <input v-model="modelValue"> -->
<!-- 4.利用计算属性!!!推荐!!!-->
<input v-model="value">
</div>
</template>
<script>
export default {
props: {
modelValue: String
},
emits: ["update:modelValue"],
computed: {
value: {
set(value) {
this.$emit("update:modelValue", value);
},
get() {
return this.modelValue;
}
}
},
methods: {
btnClick(event) {
this.$emit("update:modelValue", event.target.value);
}
}
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# 绑定多个值 🔥
<template>
<!-- 绑定两个v-model,更多的一样! -->
<hy-input v-model="message" v-model:title="title"></hy-input>
<h2>{{ message }}</h2>
<h2>{{ title }}</h2>
</template>
<script>
import HyInput from './HyInput.vue'
export default {
components: {
HyInput,
},
data() {
return {
message: 'Hello World',
title: '哈哈哈',
}
},
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<template>
<div>
<input v-model="value">
<input v-model="titleData">
</div>
</template>
<script>
export default {
props: {
modelValue: String,
title: String
},
emits: ["update:modelValue", "update:title"],
computed: {
value: {
set(value) {
this.$emit("update:modelValue", value);
},
get() {
return this.modelValue;
}
},
titleData: {
set(title) {
this.$emit("update:title", title);
},
get() {
return this.title;
}
}
}
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 注意—绑定对象 🔥
上述只能绑定1个值,不能绑定对象!否则对象属性改变不能触发set方法。详细见项目!
改成下面绑定对象写法还是有问题,解决方式:
# 方式一
直接修改父组件formData,但是浅拷贝里对象的修改不会触发
可以在父组件中不直接修改props的formData,而是修改formData中的属性!
// 父组件修改属性 formData.value.xxx = xxx
// 子组件
const formData = ref({...props.modelValue})
watch(
formData,
(newValue) => {
console.log(newValue)
emit('update:modelValue', newValue)
},
{
deep: true
}
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
不能使用computed来替代ref,配合watch会产生无限递归!
# 方式二
不适用v-model双向绑定语法糖,而是自定义!
子组件
<template>
<el-input
:model-value="modelValue[`${item.field}`]"
@update:modelValue="handleValueChange($event, item.field)"
/>
</template>
<script lang="ts" setup >
const props = defineProps({
modelValue: {
type: Object,
required: true,
}
})
const emit = defineEmits(['update:modelValue'])
const handleValueChange = (value: any, field: string) => {
emit('update:modelValue', { ...props.modelValue, [field]: value })
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
父组件直接修改 formData.value 都可以!
编辑 (opens new window)
上次更新: 2022/04/30, 01:54:50