v-model获取值与.value取值的区别(v-model原理分析)

vue中使用v-model在表单元素上创建双向数据绑定,在官方文档中简单的提到了它的本质只是一个语法糖,在单向数据绑定的基础上,增加了监听用户输入事件并更新数据的功能;
对,它本质上只是一个语法糖,但到底是一个什么样的语法糖呢……?

简单点说,如果有这样一段模板:

    <input v-model="name" type="text"/>

那么 v-model 的行为,就比较类似:

    <input :value="name" @input="name = $event.target.value" type="text"/>

前段时间刚好要做一个类似百度搜索的输入框输入后实时搜索的功能,发现使用输入法 (如中文、日文、韩文等) 的时候,v-model不会在输入法组合文字过程中得到更新,打开官方文档查找后发现文档中已经提到了这种情况。官方推荐直接使用input事件来处理。可以向下面这样写:

    <input :value="name" @getData="limit($event.target.value)" type="text"/>

 

 

 没想到前几天再次踩坑。

<input v-model="loginForm.phoneNumber" @input="limit" type="text">
limit(e) {
      e.target.value = e.target.value.replace(/[^\d]/g,'')
      console.log('value值-----'+e.target.value)
      console.log('model值-----'+this.loginForm.phoneNumber)
    }

使用了一个函数限制输入框只能输入数字,输入其他将会被置空,在输入1时是正确的,之后我们输入一个非数字,这个非数字并被置空之后,再输入新的数字,出现了下面这样的情况:

v-model的值和value的值出现了不同,v-model无法获取到新输入的数值。

 

为什么会这样呢?百度半天无果,只好研究一波vue源码。如下便是vue中实现v-model绑定的方法,可以发现,在方法中有一句判断:code = `if($event.target.composing)return;${code}` ,这是什么意思呢?即当input事件是由IME (即由输入法触发)构成触发的,会直接return,不再获取值。

function genDefaultModel (
  el: ASTElement,
  value: string,
  modifiers: ?ASTModifiers
): ?boolean {
  const type = el.attrsMap.type
  const { lazy, number, trim } = modifiers || {}
  const needCompositionGuard = !lazy && type !== 'range'
  const event = lazy
    ? 'change'
    : type === 'range'
      ? RANGE_TOKEN
      : 'input'

  let valueExpression = '$event.target.value'
  if (trim) {
    valueExpression = `$event.target.value.trim()`
  }
  if (number) {
    valueExpression = `_n(${valueExpression})`
  }

  let code = genAssignmentCode(value, valueExpression)
  if (needCompositionGuard) {
    code = `if($event.target.composing)return;${code}`
  }

  addProp(el, 'value', `(${value})`)
  addHandler(el, event, code, null, true)
  if (trim || number || type === 'number') {
    addHandler(el, 'blur', '$forceUpdate()')
  }
}

 再看代码的其他部分,并没有发现什么还可能出现问题的地方,所以直接来测试一波是否当我们输入汉字后再输入数字时,composing的判断出现了问题,导致了v-model无法获取值。

limit(e) {
      e.target.value = e.target.value.replace(/[^\d]/g,'')
      console.log('是否由输入法触发-----'+e.target.composing);
      console.log('value值-----'+e.target.value)
      console.log('model值-----'+this.loginForm.phoneNumber)
    }

果然,composing再继续输入数字时,每次判断仍然为true,导致v-model无法获取到值。

 
  • 11
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值