【问题标题】:Bind multiple events to v-on directive in Vue将多个事件绑定到 Vue 中的 v-on 指令
【发布时间】:2019-05-18 09:52:42
【问题描述】:

在 jQuery 中,您可以通过执行以下操作来绑定多个事件:

$('#myDiv').on('touchstart mousedown', // more code here

据我了解,这将同时收听touchstartmousedown。但我不知道如何用 Vue 做同样的事情。我只能做@touchstart="doSomething()"@mousedown="doSomething()"。我错过了一些明显的东西吗?谢谢

【问题讨论】:

    标签: javascript jquery vue.js vuejs2


    【解决方案1】:

    1。使用事件修饰符

    如果您依赖events,您可以尝试与event modifiers 绑定,然后将它们串联起来。比如:

    <a @click.stop="doThis" @click.right="showContextMenu"></a>
    

    2。以编程方式附加事件

    或者,您可以创建事件列表及其各自的实现以附加并使用v-on 进行循环,这是this post 的一种解决方法:

    created() {
        const EVENTS = [
          {name: 'my-event1', callback: () => console.log('event1')},
          {name: 'my-event2', callback: () => console.log('event2')},
          {name: 'my-event3', callback: () => console.log('event3')}
        ]
    
        for (let e of EVENTS) {
          this.$on(e.name, e.callback); // Add event listeners
        }
      }
    
    <button @click="$emit('my-event1')">Raise event1</button>
    <button @click="$emit('my-event2')">Raise event2</button>
    <button @click="$emit('my-event3')">Raise event3</button>
    

    3。 v-on多个值

    否则,就像您可以使用v-bind on multiple values 一样,您实际上也可以使用v-on 来处理事件。

    <div id="mydDiv" v-on="handlers"></div>
    
    // ...
    
    data() {
      const vm = this;
    
      return {
        handlers: {
          mousedown: vm.divMousedown,
          touchstart: vm.divTouchstart
        }
      }
    },
    
    methods: {
      divMousedown() {
        console.log('event: mousedown');
      },
      divTouchstart() {
        console.log('event: touched');
      }
    }
    

    如果您需要按事件类型分解处理程序,请尝试检查type while the event is being fired,因此在您的情况下,因为touchstart 似乎也会触发mousedown,也许:

    methods: {
      onTouched(evt) {
        evt.preventDefault();
    
        if (evt.type === 'mousedown') {
            // handle mousedown
        }
        else if (evt.type === 'touchstart') {
            // ...
        }
      }
    }
    

    Note:您可能想在touchmove 上调用preventDefault() 而不是touchstart。这样,鼠标事件仍然可以触发,并且链接之类的东西将继续工作。

    【讨论】:

    • 感谢您花时间写出如此全面的答案。对于我的特定用例,选项 3 看起来很有希望,但不幸的是,在触摸设备上它会触发两次事件:一次用于 touchstart,另一次用于mousedown。不幸的是,这对我来说不是一个选择,因为我需要触摸设备的触地或笔记本电脑/台式机的鼠标触地 - 不是两者兼而有之。
    • 使用对象表示法,有没有办法在事件本身之外传递额外的数据?我有一个 v-for 并希望能够做类似 v-on:"attributes" 结合属性的事情:{ click: (event, my_data) => { }, mousedown: (event, my_data) => {} }
    【解决方案2】:

    不,您没有遗漏任何明显的东西。 “touchstart mousedown”是 jQuery 为方便起见而提供的简写符号。 Vue 没有提供类似的便利(可能是因为 attrs 的事件绑定语法对于所有提供的选项已经变得非常麻烦)。

    正确的方法如您所说,使用两个单独的属性:@touchstart="doSomething()" or @mousedown="doSomething()"

    【讨论】:

    • 使用两个独立属性的问题在于,在触摸设备上它会触发两次事件:一次用于@touchstart,另一次用于@mousedown。似乎在桌面上工作正常,因为我认为桌面浏览器只是忽略了 touchstart 指令。所以不幸的是,这不是我的选择。
    • 你是对的,但是在阅读MDN touchevents section 时,我了解到你需要将preventDefault() 添加到 touchstart 事件中才能停止触发鼠标事件。所以我修改了我的代码以阅读@touchstart.prevent="buzzIn()" @mousedown="buzzIn()",这似乎解决了事件触发两次的问题。现在它只在触摸或鼠标上触发一次。
    【解决方案3】:

    vue 故意不支持绑定多个事件,因为inherent limitations in attribute names and the desire to avoid runtime overhead.

    如果您绝对必须有多事件绑定,a custom directive would be the way to go

    (以下代码无耻地从链接的 JSFiddle 复制,因为 SO 不允许链接到答案中没有代码的小提琴)

    function functionWrapper(e) {
      /* add filters to handle event type before propagating to callback function for custom event handler */
      e.target.__handler__.fn(e)
    }
    
    Vue.directive('multiEvent', {
      bind: function(el, binding, vnode) {
        el.__handler__ = binding.value
        binding.value.evt.forEach(e => el.addEventListener(e, functionWrapper))
      },
      unbind: function(el, binding) {
        el.__handler__.evt.forEach(e => el.removeEventListener(e, functionWrapper))
        el.__handler__ = null
      }
    })
    

    用法:

    <input v-multi-event="{ evt: ['click', 'blur', 'change', 'keydown'], fn: someCallback }">
    

    【讨论】:

    • 感谢您提供如此详细的答复。但不幸的是,在触摸设备上它会触发两次事件:一次为touchstart,另一次为mousedown。不幸的是,这对我来说不是一个选择,因为我需要触摸设备的触地或笔记本电脑/台式机的鼠标触地 - 不是两者兼而有之。从我的记忆中,jQuery 似乎可以毫不费力地处理这个问题。只需简单$('#myDiv').on('touchstart mousedown', // more code here
    • 那么有什么特别的理由不省略touchstart 吗?无论哪种方式,您都可以使用debounce 包装您的下游回调以防止多重触发。
    • 我需要touchstart 用于移动设备; mousedown 似乎不适用于触摸屏:(如果我理解“用去抖动包装你的下游回调以防止多触发器”意味着我可能不需要 Stack Overflow!:) 但谢谢。如果我明天恢复项目时有任何进展,我会更新此页面。
    • 我在这里很困惑。您说“在触摸设备上它会触发两次事件:一次用于touchstart,另一次用于mousedown”,现在您说“mousedown 似乎不适用于触摸屏”。这些对我来说似乎是相互排斥的。
    • 在阅读了MDN touchevents section 之后,我发现了一段说 “重要的是要注意,在许多情况下,触摸和鼠标事件都会被发送(为了让非触摸特定代码仍然与用户交互)。如果您使用触摸事件,则应调用 preventDefault() 以防止鼠标事件也被发送。” 所以我修改了我的代码以阅读 @touchstart.prevent="buzzIn()" @mousedown="buzzIn()" 这似乎已经解决了事件触发两次的问题。现在它只在触摸或鼠标上触发一次。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-03-07
    • 2018-08-25
    • 2016-12-12
    • 2021-04-23
    • 2013-01-22
    • 1970-01-01
    • 2017-12-18
    相关资源
    最近更新 更多