【问题标题】:VueJS: Why Trigger 'Input' Event Within 'Input' Event Handler?VueJS:为什么在“输入”事件处理程序中触发“输入”事件?
【发布时间】:2017-05-15 14:29:04
【问题描述】:

我正在学习 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 以它的使用方式使用,以及它为什么以它的工作方式工作。

谁能解释一下?

【问题讨论】:

  • 这种情况下的emit是将事件向上传递到父范围。

标签: vue.js emit


【解决方案1】:

这里的 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。这些基本函数调用事件以使我们作为开发人员的生活更轻松,它们是:输入、模糊、焦点。有些有专门的事件,如选择元素实现更改,表单标签实现提交。

焦点上的输入标记捕获键盘输入并显示文本输入光标以指示它已准备好接收输入。它为选项卡键码添加了处理程序,该处理程序查找下一个可用输入并将焦点转移到该元素。事件泵风格的功能系统在这里很棒,因为它允许您绑定焦点并在输入焦点时执行诸如更改背景颜色或边框之类的操作,而无需自己实现用于捕获输入或显示光标的代码。

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

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

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

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

走起来好多了:

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

而不是必须在任何地方添加value 和input 绑定:

...
<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 示例背后的一些模式和推理。

【讨论】:

  • 所以连接 updateValue 处理程序会阻止输入元素的本机输入处理?但为什么?代码没有使用“prevent”修饰符。
  • @Jay 不,它不会阻止本机处理,但本机处理只是更新显示的值。您正在将处理程序与本机处理一起添加。自定义 Web 组件没有对任何事件进行本地处理,您必须自己实现。
  • 如果原生处理只是简单地更新显示的值并且它没有被阻塞,那么为什么必须有一个 $emit 语句来让它执行呢?文档指出 $emit 在“this”实例上触发了一个事件。它在文档中的什么地方解释了它是如何触发父事件的?
  • @Jay &lt;input&gt; 的原生处理是显示更新后的值。 &lt;currency-input&gt; 上的输入事件的本机处理未定义。由于它没有被定义,你必须定义它何时被调用以及它被调用时会发生什么。 this.$emit 调用事件并允许它被事件侦听器捕获。 &lt;currency-input v-on:input='handler'&gt;&lt;/currency-input&gt; 允许您将事件处理附加到组件。如果您愿意,我可以使用有关事件泵的更详细信息更新我的答案,但 cmets 太短而无法处理。
  • @Jay 是的,就像我提到的那样,v-model='data' 与添加 v-bind:value='data' v-on:input='data = $event.target.value' 类似@.
猜你喜欢
  • 2018-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-07
  • 2021-04-18
相关资源
最近更新 更多