VueJS:为什么触发'输入'事件内'输入'事件处理程序?

时间:2017-05-15 14:29:04

标签: vue.js emit

我正在学习VueJS。我正在弄清楚他们的货币验证example code

Vue.component('currency-input', {
  template: `
    <span>
      $
      <input
        ref="input"
        v-bind:value="value"
        v-on:input="updateValue($event.target.value)">
    </span>
  `,
  props: ['value'],
  methods: {
    // Instead of updating the value directly, this
    // method is used to format and place constraints
    // on the input's value
    updateValue: function (value) {
      var formattedValue = value
        // Remove whitespace on either side
        .trim()
        // Shorten to 2 decimal places
        .slice(
          0,
          value.indexOf('.') === -1
            ? value.length
            : value.indexOf('.') + 3
        )
      // If the value was not already normalized,
      // manually override it to conform
      if (formattedValue !== value) {
        this.$refs.input.value = formattedValue
      }
      // Emit the number value through the input event
      this.$emit('input', Number(formattedValue))
    }
  }
})

updateValue函数底部的$ emit调用会触发输入事件。

当我发表评论时,实时货币验证不再有效。所以我意识到它有一个目的。

但为什么在输入事件中触发输入事件?

您认为输入事件会再次触发,导致updateValue处理程序再次触发,导致由于递归调用而导致堆栈溢出。

我理解VueJS更简单的$ emit示例代码。它就像Jquery的触发功能一样。

vm.$on('test', function (msg) {
  console.log(msg)
})
vm.$emit('test', 'hi')
// -> "hi"

但是在货币验证示例中,我不明白为什么$ emit的使用方式,以及为什么它以它的工作方式工作。

有人可以解释一下吗?

1 个答案:

答案 0 :(得分:10)

此处的Emit调用允许您在父上下文中挂钩事件。 v-model指令也使用Input事件来处理与组件的双向绑定。

v-model='model'本质上是v-bind:value='model' v-on:input='model = $event.target.value',添加了一些内容以使其发挥出色。删除this.$emit('input', Number(formattedValue))时,您将删除更新组件外部值的机制。

编辑:@Jay小心你想要的东西

HTML中的所有元素都有一系列针对常见事件的本机处理程序;调整大小,加载,卸载等等。当页面改变它的呈现并且可以被禁用或添加时,它们处理该做什么,因为JavaScript浏览器的引入使用了一个事件泵系统,允许将多个功能附加到任何事件上引发事件时按顺序运行。一个例子是如何在调整大小时运行3个函数来处理边缘情况,例如最小/最大尺寸,屏幕方向等。

表单元素通常实现自己的基本事件函数:keydown,keyup,mousedown,mouseup。这些基本函数调用事件,使我们的生活更容易作为开发人员,这些是:输入,模糊,焦点。有些事件具有专门的事件,如实现变更的选择元素,表单标签实现提交。

焦点捕捉键盘上的输入标签输入并显示文本输入光标以指示它已准备好接收输入。它为tab键代码添加了处理程序,它找到下一个可用输入并将焦点转移到该元素。事件泵样式函数系统非常棒,因为它允许您绑定到焦点并执行诸如在输入聚焦时更改背景颜色或边框等操作,而无需实现捕获输入或自己显示光标的代码。

当您键入输入标记时,输入标记也会引发input事件,表示输入已更改,告诉浏览器更改值并更新显示,以便用户期望的功能保持一致。

currency-input示例中,我们添加了updateValue函数来处理本机函数并处理事件的输入值,在updateValue函数中我们修改了字符串表示形式价值和需要某个地方来表达它。你可以简单地添加一个data属性来保存值,并将输入的value属性绑定到data属性,允许currency-input在内部处理结果的显示,但这会将值锁定在私有访问器后面,你会无法修改或检索所得货币格式化值的值。

使用this.$emit('input', Number(formattedValue)) updateValue函数通过引发可由父上下文捕获并使用的事件,类似于本机input标记。您可以将它存储在一个值中,将其用作函数的基础,或者甚至完全忽略它,尽管这可能没有多大帮助。这允许您跟踪输入的值并根据需要进行修改或将其发送到服务器,显示它等。

它还绑定了一些最有针对性的v-model指令,它是一个语法糖,允许value属性绑定和input事件绑定到当前上下文中的数据属性。通过提供value prop并发出input事件,自定义元素的行为类似于Vue应用程序系统中的本机表单元素。当您想要打包和分发或重用组件时,这是一个非常有吸引力的功能。

要好多了:

...
<currency-input v-model='dollarValue'></currency-input>
<input v-model='dollarValue'>
...

比必须添加valueinput绑定到处都是:

...
<currency-input v-bind:value='dollarValue' v-on:input='updateDollarValue($event.target.value)'></currency-input>
<input v-bind:value='dollarValue' v-on:input='updateDollarValue($event.target.value)'>
...

既然我已经完成了奇怪的漫游,我希望这有助于理解currency-input示例背后的一些模式和推理。