组件 v-model

来自Wikioe
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" />
  • update:modelValue:展开时,默认的“触发事件” ——【也是子组件需要定义的 emit】


把这个“展开形式”理解为类源码实现,子组件只需要根据该形式实现即可

💡所以,子组件中需要:

  1. 声明“属性 modelValue”,并将 <input> 的“value 属性”绑定到该属性;
  2. 声明“事件 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>

如上:

  1. 声明“属性 modelValue”和“事件 update:modelValue”;
  2. <input> 的“value 属性”绑定到“modelValue”;
  3. 监听 <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>

如上:

  1. 声明“属性 modelValue”和“事件 update:modelValue”
  2. 提供计算属性“value”:
    1. 其 getter 用于:获取“modelValue”;
    2. 其 setter 用于:用 value 触发“update:modelValue”
  3. <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"
/>