“组件 v-model”的版本间差异

来自Wikioe
跳到导航 跳到搜索
无编辑摘要
 
(未显示同一用户的1个中间版本)
第6行: 第6行:
  有点绕,做个笔记
  有点绕,做个笔记


== '''v-model 用于组件''' ==
== '''组件的 v-model 实现''' ==
  首先,需要理解 v-model 的'''等价形式'''(或者说'''展开形式''')。
  首先,需要理解 v-model 的'''等价形式'''(或者说'''展开形式''')。


v-model 应用于组件时:
与“原生元素”类似<ref>
在“原生元素”上:
: <syntaxhighlight lang="HTML" highlight="">
<input v-model="searchText" />
</syntaxhighlight>
: 会被展开为:
: <syntaxhighlight lang="HTML" highlight="">
<input
  :value="searchText"
  @input="searchText = $event.target.value"
/>
</syntaxhighlight>
</ref>,将 v-model 应用于组件时:
: <syntaxhighlight lang="HTML" highlight="">
: <syntaxhighlight lang="HTML" highlight="">
<CustomInput v-model="searchText" />
<CustomInput v-model="searchText" />
第30行: 第42行:
# <span style="color: blue">声明“'''事件 update:modelValue'''”,并让 <code><input></code> 的“'''input 事件'''”用“<code><input></code> 的新值”触发该事件。</span>
# <span style="color: blue">声明“'''事件 update:modelValue'''”,并让 <code><input></code> 的“'''input 事件'''”用“<code><input></code> 的新值”触发该事件。</span>


=== 子组件的实现('''方式一''') ===
=== 组件的实现('''方式一''') ===
依据“展开形式”实现子组件,如下:
依据“展开形式”实现子组件,如下:
: <syntaxhighlight lang="HTML" highlight="">
: <syntaxhighlight lang="HTML" highlight="">
第50行: 第62行:
# 监听 <code><input></code> 的“input 事件”,以携带“<code><input></code>的新值”(即,<code>$event.target.value</code>)触发“update:modelValue”。
# 监听 <code><input></code> 的“input 事件”,以携带“<code><input></code>的新值”(即,<code>$event.target.value</code>)触发“update:modelValue”。


=== 子组件的实现('''方式二''') ===
=== 组件的实现('''方式二''') ===
以“v-model”替换该“展开形式”实现子组件,如下:
以“v-model”替换该“展开形式”实现子组件,如下:
: <syntaxhighlight lang="HTML" highlight="">
: <syntaxhighlight lang="HTML" highlight="">
第171行: 第183行:
</syntaxhighlight>
</syntaxhighlight>


== '''v-model:自定义修饰符''' ==
== '''v-model:自定义修饰符<ref>对于“指令及其修饰符”的理解,参考:[https://cn.vuejs.org/guide/reusability/custom-directives.html Vue.js:《自定义指令》]</ref>''' ==
  v-model 有一些内置的修饰符,例如 <code>.trim</code>,<code>.number</code> 和 <code>.lazy</code>。
  v-model 有一些内置的修饰符,例如 <code>.trim</code>,<code>.number</code> 和 <code>.lazy</code>。
   
   
第240行: 第252行:
</syntaxhighlight>
</syntaxhighlight>


== ==
== 参考 ==
在“原生元素”上:
<references/>
: <syntaxhighlight lang="HTML" highlight="">
<input v-model="searchText" />
</syntaxhighlight>
会被展开为:
: <syntaxhighlight lang="HTML" highlight="">
<input
  :value="searchText"
  @input="searchText = $event.target.value"
/>
</syntaxhighlight>

2023年3月29日 (三) 12:36的最新版本


关于

参考:Vue官方文档:《组件 v-model》

有点绕,做个笔记

组件的 v-model 实现

首先,需要理解 v-model 的等价形式(或者说展开形式)。

与“原生元素”类似[1],将 v-model 应用于组件时:

<CustomInput v-model="searchText" />
会被展开为:
<CustomInput
  :modelValue="searchText"
  @update:modelValue="newValue => searchText = newValue"
/>

👉相当于:将子组件的属性“modelValue”绑定到响应式状态 searchText,并监听事件“update:modelValue”以新值替换 searchText


不需要考虑背后是什么原理,只需要根据该形式,完成子组件即可

💡所以,子组件中需要:

  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:参数

v-model 的参数,用于指定v-model 绑定于“组件的哪个 prop”

——【是否使用参数,需要根据组件实现来定(组件的 <input> 的 value 绑定于哪个 prop)】
——【v-model 默认绑定于组件的“modelValue”属性,其对应的事件为“update:modelValue”】(如上节)

类似的:

<CustomInput v-model:pram="searchText" />

: 会被展开为:

<CustomInput
  :theSpecialProp="searchText"
  @update:theSpecialProp="newValue => searchText = newValue"
/>

多 v-model 绑定

对于“存在多个 <input> 的子组件”,只需要使用多个“带参数的 v-model”,以分别与子组件的 prop 绑定即可。

【两种写法,同上一节】

对于:

<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>

v-model:自定义修饰符[2]

v-model 有一些内置的修饰符,例如 .trim.number.lazy。

但某些时候,需要 v-model 支持自定义的修饰符。

v-model 自定义修饰符:

  1. “自定义修饰符”可以通过在 defineProps 中定义 prop 来捕获。
    • 对于默认 prop“modelValue”,定义“修饰符 prop”为“modelModifiers
    • 对于其他 prop,定义“修饰符 prop”为“prop名称 + Modifiers” —— 如:title 的“修饰符 prop”为 titleModifiers
  2. “自定义修饰符”的效果,可以套在 <input> 的事件处理外完成。

示例一:无参数的 v-model 修饰符

对于以下代码,通过 capitalize 修饰符使输入内容的首字母大写:

  <MyComponent v-model.capitalize="myText" />

对应子组件的实现为:

<script setup>
const props = defineProps({
  modelValue: String,
  modelModifiers: { default: () => ({}) }
})

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

function emitValue(e) {
  let value = e.target.value
  if (props.modelModifiers.capitalize) {
    value = value.charAt(0).toUpperCase() + value.slice(1)
  }
  emit('update:modelValue', value)
}
</script>

<template>
  <input type="text" :value="modelValue" @input="emitValue" />
</template>

示例二:有参数的 v-model 修饰符

对于以下代码,通过 capitalize 修饰符使输入内容的首字母大写:

  <MyComponent v-model:title.capitalize="myText" />

对应子组件的实现为:

<script setup>
const props = defineProps({
  title: String,
  titleModifiers: { default: () => ({}) }
})

const emit = defineEmits(['update:title'])

function emitValue(e) {
  let value = e.target.value
  if (props.titleModifiers.capitalize) {
    value = value.charAt(0).toUpperCase() + value.slice(1)
  }
  emit('update:title', value)
}
</script>

<template>
  <input type="text" :value="title" @input="emitValue" />
</template>

参考

  1. 在“原生元素”上:
    <input v-model="searchText" />
    
    会被展开为:
    <input
      :value="searchText"
      @input="searchText = $event.target.value"
    />
    
  2. 对于“指令及其修饰符”的理解,参考:Vue.js:《自定义指令》