(划重点)v-model的实现(Vue2和Vue3),change、blur、input事件。

本文探讨了v-model在Vue2和Vue3中的工作原理,指出它是一个语法糖。在Vue2中,针对不同输入元素v-model会绑定不同的属性和事件。Vue3对v-model进行了重写,允许绑定多个v-model。文章详细阐述了change、blur、input事件的差异,并介绍了修饰符如.lazy、.number和.trim的作用。同时,分析了Vue2中自定义组件如何实现双向绑定,以及Vue3如何通过update:xxx事件支持多个v-model。

在学习中了解到,v-model实际上只是一个语法糖。并且Vue3对v-model的逻辑进行了重写。于是决定对Vue2和Vue3中对于v-model的实现进行探究。

v-model中触发的事件

v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件:

text 和 textarea 元素使用 value propertyinput 事件
checkbox 和 radio 使用 checked propertychange 事件
select 字段将 value 作为 prop 并将 change 作为事件

change、blur、input事件

  • change事件:只有当内容变化,并且失去焦点时才触发。没有实时性
  • input事件:在输入框输入的时候回实时响应并触发。
  • blur事件:失去焦点触发。

修饰符

  • .lazy 将触发的input事件改为触发change事件。
  • .number 将输入值转为number类型。
  • .trim 去除输入值的首位空格。

Vue2中v-model的实现(以text为例)

普通的Dom元素(原生组件)
$event是指当前触发的是什么事件(鼠标事件,键盘事件等)
$event.target则指的是事件触发的目标,即哪一个元素触发了事件,这将直接获取该dom元素

<input v-model="val">
<input :value="val" @input="val = $event.target.value">

自定义组件
如果作为子组件使用,在父组件中想实现双向绑定要怎么实现呢?
不妨先将父组件调用子组件的v-model用自己的写法重写再分析。

重写
在input中输入的值是回调函数的第一个参数(emit带回来的第一个值),所以可以用arguments对象取到。从这里我们可以有个思路,自定义组件要实现双向绑定需要满足两件事:1、子组件要接受父组件传递过来的值。2、子组件input中发生相应的修改事件后,要抛出事件,并将value值给带回来。

<component v-model="val">
<component :value="val" @input="val = arguments[0]"

子组件中的写法
在vue2中,有一个model的属性可以定义接受的属性以及外抛的事件。这个接收的属性要和传入的属性相对应起来。
这里要注意一点,如果按我下面这样写,似乎model这个属性没什么用,因为一切都是子组件和父组件的值一一对应的。但是实际情况是,正常的使用下我们并不会将父组件那一部分拆开,而是直接使用v-model了。所以model的作用就是将父子组件之间,传入的值和触发的事件一一对应起来(所以prop要和props里面获取的值一样)。

<input type="text" :value="value" @input="$emit('input',$event.target.value)">

model: {
  prop: 'value',
  event: 'input'
}
props: {
  value: String
}

但是我们也可以发现一个问题,由于传入的值和model中的prop必须是对应的,所以一次只能绑定一个v-model。

Vue3,重写了v-model,可以绑定多个v-model

移除了model
prop默认值改为了modelValue
event默认值改为了update:modelValue
总结一下,就是可以通过v-model:xxx的方式,然后通过抛出的方法update:xxx来实现多个v-model的绑定
转载的代码,原链接

//父组件
<template>
  <div>
    <Child v-model:text="message" />
    <div>绑定的值:{{message}}</div>
  </div>
</template>

//子组件
<template>
  <div>
    <input 
      type="text" 
      :value="text" 
      @input="$emit('update:text', $event.target.value)"
    >
  </div>
</template>
<script>
export default {
  //3.x 接收v-model冒号后面的值,相应的触发的方法改为update:text
  props:['text']
}
</script>
//父组件
<template>
  <div>
    <Child 
      v-model="message1"
      v-model:text="message2" 
    />
    <div>绑定的值1{{message1}}</div>
    <div>绑定的值2{{message2}}</div>
  </div>
</template>

//子组件
<template>
  <div>
    <input 
      type="text" 
      :value="modelValue" 
      @input="$emit('update:modelValue', $event.target.value)"
    >
    <input 
      type="text" 
      :value="text" 
      @input="$emit('update:text', $event.target.value)"
    >
  </div>
</template>
<script>
export default {
  //v-model冒号后面不写值,默认就是modelValue
  props:['modelValue','text']
}
</script>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值