vue3中v-model的原理

1.v-model的实现方式

v-model在Vue.js中是一个语法糖,它实际上是:modelValue@input事件的组合。具体来说,v-model做了以下几件事情:

  1. 初始化绑定:当Vue实例创建时,它会解析模板中的v-model指令,并找到对应的表单元素。然后,它会将该表单元素的value属性与Vue实例中的某个数据属性(如data中的某个属性)进行绑定。这通常是通过Proxy来实现的,以实现对数据属性的劫持和监听。

  2. 监听输入事件:Vue还会为该表单元素添加一个input事件监听器。当用户在表单元素中输入内容时,会触发input事件,Vue会捕获到这个事件,并获取用户输入的值。

  3. 更新数据:Vue将用户输入的值更新到之前绑定的数据属性中。由于Vue的数据响应系统,这个数据属性的变化会自动触发视图的更新,从而实现双向数据绑定。

<template>
  //编译前
  <input v-model='msg'/>
  //vue会将其编译为
  <input :value='msg' @input='msg = (<HTMLInputElement>$event.target).value'>
</template>

<script lang='ts' setup>
import {ref} from 'vue'

const msg = ref('')
</script>

2.示例说明

一般在开发中我们会把v-model绑定在自定义组件上,以扩展了其灵活性和适用性。

以下是一个自定义组件支持 v-model 的例子:

//MyInput.vue
<template>
  <input 
    :value="modelValue" 
    @input="emit('update:modelValue', (<HTMLInputElement>$event.target).value)
  ">
</template>

<script lang='ts' name='MyInput' setup>

defineProps(['modelValue'])

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

</script>

 在父组件中使用这个自定义组件时,可以这样写:

//Father.vue
<template>
  //编译前
  <MyInput v-model="msg"></MyInput>
  //vue会将其编译为
  <MyInput :modelValue="msg" @update:modelValue="msg = $event"></MyInput>
</template>

<script lang='ts' name='Father' setup>
import MyInput from './MyInput.vue';
import {ref} from 'vue'

const msg = ref('hello')
</script>

注意:

  • 对于原生事件,$event就是事件对象(这里对应着MyInput.vue中的$event)。
  • 对于自定义事件,$event就是触发事件时,所传递的数据(这里对应着Father.vue中的$event)。

 在父组件中,我们还可以使用 v-model 配置来指定自定义的 propevent 名称:

//Father.vue
<template>
  //编译前
  <MyInput v-model:msg="msg"></MyInput>
  //vue会将其编译为
  <MyInput :msg="msg" @update:msg="msg = $event"></MyInput>
</template>

<script lang='ts' name='Father' setup>
import MyInput from './MyInput.vue';
import {ref} from 'vue'

const msg = ref('hello')
</script>

这里 v-model:msg 告诉 Vue 使用 msg作为 propupdate:msg作为事件名。 

//MyInput.vue
<template>
  <input 
    :value="msg" 
    @input="emit('update:msg', (<HTMLInputElement>$event.target).value)
  ">
</template>

<script lang='ts' name='MyInput' setup>

defineProps(['msg'])

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

</script>

 这样的用法可以使组件的扩展性更高,还可以为一个自定义组件绑定多个v-model:

//Father.vue
<template>
  <MyInput 
     v-model:username="username" 
     v-model:password="password"
  ></MyInput>
</template>

<script lang='ts' name='Father' setup>
import MyInput from './MyInput.vue';
import {ref} from 'vue'

const username = ref('admin')

const password= ref('123456')
</script>

在自定义组件 MyInput.vue 中: 

//MyInput.vue
<template>
  <input 
    :value="username" 
    @input="emit('update:username', (<HTMLInputElement>$event.target).value)
  ">
  <input 
    :value="password" 
    @input="emit('update:password', (<HTMLInputElement>$event.target).value)
  ">
</template>

<script lang='ts' name='MyInput' setup>

defineProps(['username','password'])

const emit = defineEmits(['update:username','update:password'])

</script>

总结来说,v-model 的底层原理主要是通过属性绑定和事件监听来实现双向数据绑定,并且通过自定义组件扩展了其灵活性和适用性。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值