“组件 v-model”的版本间差异
跳到导航
跳到搜索
无编辑摘要 |
|||
(未显示同一用户的3个中间版本) | |||
第6行: | 第6行: | ||
有点绕,做个笔记 | 有点绕,做个笔记 | ||
== '''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" /> | ||
第22行: | 第34行: | ||
<big>👉</big>相当于:将子组件的属性“modelValue”绑定到响应式状态 searchText,并监听事件“update:modelValue”以新值替换 searchText | <big>👉</big>相当于:将子组件的属性“modelValue”绑定到响应式状态 searchText,并监听事件“update:modelValue”以新值替换 searchText | ||
不需要考虑背后是什么原理,<span style="color: blue; font-size:120%">'''只需要根据该形式,完成子组件即可'''</span>。 | |||
<big>💡</big>所以,子组件中需要: | <big>💡</big>所以,子组件中需要: | ||
# <span style="color: blue">声明“'''属性 modelValue'''”,并将 <code><input></code> 的“'''value 属性'''”绑定到该属性;</span> | # <span style="color: blue">声明“'''属性 modelValue'''”,并将 <code><input></code> 的“'''value 属性'''”绑定到该属性;</span> | ||
# <span style="color: blue">声明“'''事件 update:modelValue''' | # <span style="color: blue">声明“'''事件 update:modelValue'''”,并让 <code><input></code> 的“'''input 事件'''”用“<code><input></code> 的新值”触发该事件。</span> | ||
=== | === 组件的实现('''方式一''') === | ||
依据“展开形式”实现子组件,如下: | 依据“展开形式”实现子组件,如下: | ||
: <syntaxhighlight lang="HTML" highlight=""> | : <syntaxhighlight lang="HTML" highlight=""> | ||
第54行: | 第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=""> | ||
第84行: | 第92行: | ||
# 将<code><input></code>双向绑定到“value”。 | # 将<code><input></code>双向绑定到“value”。 | ||
== | == '''v-model:参数''' == | ||
对于“存在多个 <code><input></code> | v-model 的参数,用于指定<span style="color: blue">'''v-model 绑定于“组件的哪个 prop”'''</span> | ||
——【是否使用参数,需要根据组件实现来定(组件的 <input> 的 value 绑定于哪个 prop)】 | |||
——【v-model 默认绑定于组件的“'''modelValue'''”属性,其对应的事件为“'''update:modelValue'''”】(如上节) | |||
类似的: | |||
: <syntaxhighlight lang="HTML" highlight=""> | |||
<CustomInput v-model:pram="searchText" /> | |||
: 会被展开为: | |||
<CustomInput | |||
:theSpecialProp="searchText" | |||
@update:theSpecialProp="newValue => searchText = newValue" | |||
/> | |||
</syntaxhighlight> | |||
=== '''多 v-model 绑定''' === | |||
对于“存在多个 <code><input></code> 的子组件”,只需要使用多个“'''带参数的 v-model'''”,以分别与子组件的 prop 绑定即可。 | |||
【两种写法,同上一节】 | |||
对于: | 对于: | ||
第96行: | 第122行: | ||
/> | /> | ||
</syntaxhighlight> | </syntaxhighlight> | ||
子组件的实现('''方式一'''): | |||
: <syntaxhighlight lang="HTML" highlight=""> | : <syntaxhighlight lang="HTML" highlight=""> | ||
<script setup> | <script setup> | ||
第122行: | 第146行: | ||
</template> | </template> | ||
</syntaxhighlight> | </syntaxhighlight> | ||
子组件的实现('''方式二'''): | |||
: <syntaxhighlight lang="HTML" highlight=""> | : <syntaxhighlight lang="HTML" highlight=""> | ||
<script setup> | <script setup> | ||
第160行: | 第183行: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== ''' | == '''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>。 | ||
第167行: | 第190行: | ||
v-model 自定义修饰符: | v-model 自定义修饰符: | ||
# “自定义修饰符”可以通过在 <code>defineProps</code> 中定义 prop 来捕获。 | # “自定义修饰符”可以通过在 <code>defineProps</code> 中定义 prop 来捕获。 | ||
#* 对于默认 | #* 对于默认 prop“'''modelValue'''”,定义“修饰符 prop”为“'''modelModifiers'''” | ||
#* 对于其他 prop,定义“修饰符 prop”为“prop名称 + Modifiers” —— | #* 对于其他 prop,定义“修饰符 prop”为“prop名称 + Modifiers” —— 如:'''title''' 的“修饰符 prop”为 '''titleModifiers''' | ||
# “自定义修饰符”的效果,可以套在 <code><input></code> 的事件处理外完成。 | # “自定义修饰符”的效果,可以套在 <code><input></code> 的事件处理外完成。 | ||
第229行: | 第252行: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== | == 参考 == | ||
<references/> | |||
</ |
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
不需要考虑背后是什么原理,只需要根据该形式,完成子组件即可。
💡所以,子组件中需要:
- 声明“属性 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:参数
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 自定义修饰符:
- “自定义修饰符”可以通过在
defineProps
中定义 prop 来捕获。- 对于默认 prop“modelValue”,定义“修饰符 prop”为“modelModifiers”
- 对于其他 prop,定义“修饰符 prop”为“prop名称 + Modifiers” —— 如:title 的“修饰符 prop”为 titleModifiers
- “自定义修饰符”的效果,可以套在
<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>
参考
- ↑
在“原生元素”上:
<input v-model="searchText" />
- 会被展开为:
<input :value="searchText" @input="searchText = $event.target.value" />
- ↑ 对于“指令及其修饰符”的理解,参考:Vue.js:《自定义指令》