组件 v-model
Eijux(讨论 | 贡献)2023年3月28日 (二) 19:27的版本 (创建页面,内容为“category:Vue == 关于 == 参考:[https://cn.vuejs.org/guide/components/v-model.html Vue官方文档:《组件 v-model》] 有点绕,做个笔记 == v-model 用于组件 == 首先,需要理解 v-model 的'''等价形式'''。 在组件上: : <syntaxhighlight lang="HTML" highlight=""> <CustomInput v-model="searchText" /> </syntaxhighlight> : 会被展开为: : <syntaxhighlight lang="HTML" highlight=""> <CustomInput :modelValue="searchTe…”)
关于
参考:Vue官方文档:《组件 v-model》 有点绕,做个笔记
v-model 用于组件
首先,需要理解 v-model 的等价形式。
在组件上:
<CustomInput v-model="searchText" />
- 会被展开为:
<CustomInput :modelValue="searchText" @update:modelValue="newValue => searchText = newValue" />
👉相当于:将子组件的属性“modelValue”绑定到响应式状态 searchText,并监听事件“update:modelValue”以新值替换 searchText
- modelValue:展开时,默认的“prop” ——【也是子组件需要定义的 prop】
- 如果子组件中指定了其他 prop,则使用时需要指明 v-model 使用的 prop:
<MyComponent v-model:otherProp="searchText" />
- 如果子组件中指定了其他 prop,则使用时需要指明 v-model 使用的 prop:
- update:modelValue:展开时,默认的“触发事件” ——【也是子组件需要定义的 emit】
把这个“展开形式”理解为类源码实现,子组件只需要根据该形式实现即可。
💡所以,子组件中需要:
- 声明“属性 modelValue”,并将
<input>
的“value 属性”绑定到该属性; - 声明“事件 update:modelValue”,并使
<input>
的“input 事件”携带“<input>
的新值”触发该事件。
子组件的实现(方式一)
依据“展开形式”实现子组件,如下:
<script setup> defineProps(['modelValue']) defineEmits(['update:modelValue']) </script> <template> <input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" /> </template>
如上:
- 声明“属性 modelValue”和“事件 update:modelValue”;
- 将
<input>
的“value 属性”绑定到“modelValue”; - 监听
<input>
的“input 事件”,以携带“<input>
的新值”(即,$event.target.value
)触发“update:modelValue”。
子组件的实现(方式二)
以“v-model”替换该“展开形式”实现子组件,如下:
<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>
如上:
- 声明“属性 modelValue”和“事件 update:modelValue”
- 提供计算属性“value”:
- 其 getter 用于:获取“modelValue”;
- 其 setter 用于:用 value 触发“update:modelValue”
- 将
<input>
双向绑定到“value”。
多个 v-model 用于组件
对于“存在多个 <input>
的子组件”,需要使用多个 v-model,且需指明 v-model 分别作用与“子组件哪个属性”。
【原理同上一节】
对于:
<UserName v-model:first-name="first" v-model:last-name="last" />
子组件的实现如下。
子组件的实现(方式一)
<script setup> defineProps({ firstName: String, lastName: String }) defineEmits(['update:firstName', 'update:lastName']) </script> <template> <input type="text" :value="firstName" @input="$emit('update:firstName', $event.target.value)" /> <input type="text" :value="lastName" @input="$emit('update:lastName', $event.target.value)" /> </template>
子组件的实现(方式二)
<script setup> import { computed } from 'vue' const props = defineProps({ firstName: String, lastName: String }) const emit = defineEmits(['update:firstName', 'update:lastName']) const computedFirstName = computed({ get() { return props.firstName }, set(computedFirstName) { emit('update:firstName', computedFirstName) } }) const computedLastName = computed({ get() { return props.lastName }, set(computedLastName) { emit('update:lastName', computedLastName) } }) </script> <template> <input type="text" v-model="computedFirstName"/> <input type="text" v-model="computedLastName"/> </template>
附
在“原生元素”上:
<input v-model="searchText" />
会被展开为:
<input :value="searchText" @input="searchText = $event.target.value" />