【Vue】Vue3.0(二十二) v-model 在原始Dom元素、自定义输入组件中双向绑定的底层实现原理详解
上篇文章 【Vue】Vue3.0(二十一)Vue 3.0中 的$event使用示例
🏡作者主页:点击!
🤖Vue专栏:点击!
⏰️创作时间:2024年11月11日17点30分
v-model
底层实现的详细解释:
1. v-model
用于 HTML 标签时的底层原理
当 v-model
用于普通的 HTML 输入标签(如 <input type="text">
)时,它实际上是一种语法糖,背后做了以下几件事:
- 数据绑定:
v-model
会将输入框的value
属性与 Vue 实例中的数据属性进行绑定。在上述Father.vue
中,v-model="username"
会将输入框的value
和username
建立双向数据绑定关系。这意味着当username
的值发生变化时,输入框的value
会自动更新,反之亦然。
- 事件监听:
- 同时,
v-model
会自动为输入框添加input
事件监听器。当用户在输入框中输入内容时,input
事件会被触发,然后事件处理函数会获取输入框的最新值,并将其更新到对应的 Vue 实例数据属性中。在底层,Vue 会自动处理这个更新过程,确保数据的一致性。
- 同时,
2. v-model
用于自定义组件时的底层原理
当 v-model
用于自定义组件(如 <AtguiguInput>
)时,它的实现方式略有不同,但遵循一定的约定:
modelValue
prop 和update:modelValue
事件:- 自定义组件需要通过名为
modelValue
的prop
来接收父组件传递的值,这类似于普通v-model
中的数据绑定部分。在AtguiguInput.vue
中,通过defineProps(['ming', 'mima'])
接收了父组件传递的ming
和mima
,这里的ming
和mima
就类似于modelValue
的作用,用于接收父组件的数据。 - 当子组件内部的数据发生变化时,需要通过触发名为
update:modelValue
的自定义事件来通知父组件更新数据。在AtguiguInput.vue
中,通过emit('update:ming', (<HTMLInputElement>$event.target).value)
和emit('update:mima', (<HTMLInputElement>$event.target).value)
实现了这一点,当输入框的input
事件触发时,会将最新的值通过相应的update
事件传递给父组件。
- 自定义组件需要通过名为
3. 自定义 v-model
修饰符的底层实现
在 Father.vue
中,使用了自定义的 v-model
修饰符 ming
和 mima
,这是对 v-model
功能的一种扩展:
- 自定义绑定和事件:
- 通过
v-model:ming="username"
和v-model:mima="password"
,Vue 会将username
和password
分别与子组件中的ming
和mima
进行绑定,并监听对应的update:ming
和update:mima
事件来更新数据。这种自定义修饰符的方式允许开发者根据具体需求灵活地定义数据绑定和事件更新的逻辑,使得v-model
在不同的场景下能够更精准地满足业务需求。
- 通过
4. 与响应式系统的结合
无论是用于 HTML 标签还是自定义组件,v-model
的底层实现都与 Vue 的响应式系统紧密结合:
- 数据更新的响应式传播:
- 当输入框的值发生变化并更新了 Vue 实例中的数据属性时,Vue 的响应式系统会检测到这个变化,并自动触发相关的 DOM 更新操作,确保所有依赖于该数据属性的视图部分都能得到及时更新。同样,当 Vue 实例中的数据属性在其他地方被修改时,绑定的输入框也会相应地更新显示,从而实现了数据和视图的双向同步更新,保持了整个应用的状态一致性。
综上所述,v-model
的底层实现通过数据绑定、事件监听、自定义事件触发以及与响应式系统的协作,为开发者提供了一种简洁而强大的双向数据绑定机制,无论是在普通的 HTML 表单元素还是自定义组件中,都能方便地实现数据与视图之间的交互和同步。
代码示例:
AtguiguInput.vue
<template>
<input
type="text"
:value="ming"
@input="emit('update:ming', (<HTMLInputElement>$event.target).value)"
>
<br>
<input
type="text"
:value="mima"
@input="emit('update:mima', (<HTMLInputElement>$event.target).value)"
>
</template>
<script setup lang="ts" name="AtguiguInput">
defineProps(['ming', 'mima'])
const emit = defineEmits(['update:ming', 'update:mima'])
</script>
<style scoped>
input {
border: 2px solid black;
background-image: linear-gradient(45deg, red, yellow, green);
height: 30px;
font-size: 20px;
color: white;
}
</style>
Father.vue
<template>
<div class="father">
<h3>父组件</h3>
<h4>{{ username }}</h4>
<h4>{{ password }}</h4>
<!-- v-model用在html标签上 -->
<!-- <input type="text" v-model="username"> -->
<!-- <input type="text" :value="username" @input="username = (<HTMLInputElement>$event.target).value"> -->
<!-- v-model用在组件标签上 -->
<!-- <AtguiguInput v-model="username"/> -->
<!-- <AtguiguInput
:modelValue="username"
@update:modelValue="username = $event"
/> -->
<!-- 修改modelValue -->
<AtguiguInput
v-model:ming="username"
v-model:mima="password"
/>
</div>
</template>
<script setup lang="ts" name="Father">
import { ref } from "vue";
import AtguiguInput from './AtguiguInput.vue'
// 数据
let username = ref('zhansgan')
let password = ref('123456')
</script>
<style scoped>
.father {
padding: 20px;
background-color: rgb(165, 164, 164);
border-radius: 10px;
}
</style>
详解:
1.
<!-- 使用v-model指令 -->
<input type="text" v-model="userName">
<!-- v-model的本质是下面这行代码 -->
<input
type="text"
:value="userName"
@input="userName =(<HTMLInputElement>$event.target).value"
>
-
组件标签上的
v-model
的本质::moldeValue
+update:modelValue
事件。<!-- 组件标签上使用v-model指令 --> <AtguiguInput v-model="userName"/> <!-- 组件标签上v-model的本质 --> <AtguiguInput :modelValue="userName" @update:model-value="userName = $event"/>
AtguiguInput
组件中:<template> <div class="box"> <!--将接收的value值赋给input元素的value属性,目的是:为了呈现数据 --> <!--给input元素绑定原生input事件,触发input事件时,进而触发update:model-value事件--> <input type="text" :value="modelValue" @input="emit('update:model-value',$event.target.value)" > </div> </template> <script setup lang="ts" name="AtguiguInput"> // 接收props defineProps(['modelValue']) // 声明事件 const emit = defineEmits(['update:model-value']) </script>
-
也可以更换
value
,例如改成abc
<!-- 也可以更换value,例如改成abc--> <AtguiguInput v-model:abc="userName"/> <!-- 上面代码的本质如下 --> <AtguiguInput :abc="userName" @update:abc="userName = $event"/>
AtguiguInput
组件中:<template> <div class="box"> <input type="text" :value="abc" @input="emit('update:abc',$event.target.value)" > </div> </template> <script setup lang="ts" name="AtguiguInput"> // 接收props defineProps(['abc']) // 声明事件 const emit = defineEmits(['update:abc']) </script>
-
如果
value
可以更换,那么就可以在组件标签上多次使用v-model
<AtguiguInput v-model:abc="userName" v-model:xyz="password"/>
原文地址:https://blog.csdn.net/qq_39666711/article/details/143691211
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!