VueJS 事件处理

  • 为什么在 HTML 中监听事件

    你可能注意到这种事件监听的方式违背了关注点分离(separation of concern)传统理念。不必担心,因为所有的 Vue.js 事件处理方法和表达式都严格绑定在当前视图的 ViewModel 上,它不会导致任何维护上的困难。实际上,使用 v-on 有几个好处:
    1. 扫一眼 HTML 模板便能轻松定位在 JavaScript 代码里对应的方法。
    2. 因为你无须在 JavaScript 里手动绑定事件,你的 ViewModel 代码可以是非常纯粹的逻辑,和 DOM 完全解耦,更易于测试。
    3. 当一个 ViewModel 被销毁时,所有的事件处理器都会自动被删除。你无须担心如何自己清理它们。
  • 如何监听 DOM 事件

    我们可以使用 v-on 指令来监听 DOM 事件并在触发事件时运行一些JavaScript
    <div id="example-1">
       <button v-on:click="counter += 1">增加 1</button>
       <p>这个按钮被点击了 {{ counter }} 次。</p>
    </div>
    <script>
       var example1 = new Vue({
          el: '#example-1',
          data: {
             counter: 0
          }
       });
    </script>
    
    尝试一下
    不过,许多事件处理程序的逻辑会更加复杂,因此将 JavaScript 保持在 v-on 属性的值中是不可行的。 这就是为什么 v-on 还可以接受您要调用的方法名称的原因。
    <div id="example-2">
       //“greet” 是下面定义的方法的名称
       <button v-on:click="greet">greet</button>
    </div>
    <script>
       var example2 = new Vue({
          el: '#example-2',
          data: {
          name: 'Vue.js'
          },
          // 在“方法”对象下定义方法
          methods: {
          greet: function (event) {
             // `this` 内部方法指向Vue实例
             alert('Hello ' + this.name + '!')
             // `event` 是本DOM事件
             if (event) {
                alert(event.target.tagName)
             }
          }
          }
       });
    </script>
    
    尝试一下
    除了直接绑定到方法名称之外,我们还可以在嵌入式 JavaScript 语句中使用方法:
    <div id="example-3">
       <button v-on:click="say('hi')">Say hi</button>
       <button v-on:click="say('what')">Say what</button>
    </div>
    <script>
       new Vue({
          el: '#example-3',
          methods: {
             say: function (message) {
                alert(message)
             }
          }
       });
    </script>
    
    尝试一下
    有时我们还需要在内联语句处理程序中访问原始 DOM 事件。 您可以使用特殊的 $event 变量将其传递给方法:
    //HTML
    <button v-on:click="warn('表格尚未提交。', $event)">Submit</button>
    
    //JS
    methods: {
       warn: function (message, event) {
       // 现在我们可以访问本机事件
       if (event) {
          event.preventDefault()
       }
          alert(message)
       }
    }
    
  • 如何监听 DOM 事件

    在事件处理程序中调用 event.preventDefault()event.stopPropagation() 是非常常见的需求。 尽管我们可以轻松地在方法内部执行此操作,但最好是这些方法可以纯粹与数据逻辑有关,而不是必须处理 DOM 事件详细信息。
    为了解决此问题,Vuev-on 提供了事件修饰符。 回想一下修饰符是用点表示的指令后缀。
    • .stop
    • .prevent
    • .capture
    • .self
    • .once
    • .passive
    // 阻止单击事件冒泡
    <a v-on:click.stop="doThis"></a>
    
    // 提交事件不再重载页面
    <form v-on:submit.prevent="onSubmit"></form>
    
    // 修饰符可以串联 
    <a v-on:click.stop.prevent="doThat"></a>
    
    // 只有修饰符 
    <form v-on:submit.prevent></form>
    
    // 添加事件侦听器时使用事件捕获模式
    <div v-on:click.capture="doThis">...</div>
    
    // 只当事件在该元素本身(而不是子元素)触发时触发回调
    <div v-on:click.self="doThat">...</div>
    
    使用修饰符时顺序很重要,因为相关代码以相同顺序生成。 因此,使用 v-on:click.prevent.self 将阻止所有单击,而 v-on:click.self.prevent 将仅防止单击元素本身。
    .once 与其他修饰符(本机DOM事件专用)不同,.once 修饰符还可以用于组件事件。
    // click 事件只能点击一次,2.1.4版本新增
    <div v-on:click.once="doThis">...</div>
    
    Vue 还提供了 .passive 修饰符,与 addEventListener 的被动选项相对应。
    .passive 修饰符对于提高移动设备的性能特别有用。
    // 滚动事件的默认行为(滚动)将发生
    // 立即,而不是等待onScroll完成
    // 如果它包含`event.preventDefault()`
    <div v-on:scroll.passive="onScroll">...</div>
    
    请勿同时使用 .passive 和 .prevent,因为 .prevent 将被忽略,并且您的浏览器可能会向您显示警告。 请记住,.passive 会与您的浏览器进行通信,您不想阻止该事件的默认行为。
  • 按键修饰符

    当需要旧版浏览器支持时,Vue 为最常用的键代码提供别名:
    • .enter
    • .tab
    • .delete (捕获 "删除" 和 "退格" 键)
    • .esc
    • .space
    • .up
    • .down
    • .ctrl (2.1.0+版本新增)
    • .alt (2.1.0+版本新增)
    • .shift (2.1.0+版本新增)
    • .meta (2.1.0+版本新增)
    • .left (2.2.0+版本新增)
    • .right (2.2.0+版本新增)
    • .middle (2.2.0+版本新增)
    • .exact (2.5.0+版本新增)
    示例:
    // Alt + C
    <input @keyup.alt.67="clear">
    
    // Ctrl + Click
    <div @click.ctrl="doSomething">Do something</div>
    
    // 即使同时按下Alt或Shift也会触发
    <button @click.ctrl="onClick">A</button>
    //仅在按Ctrl键且未按下其他任何键时才会触发
    <button @click.ctrl.exact="onCtrlClick">A</button>
    //仅当未按下系统修改器时才会触发
    <button @click.exact="onClick">A</button>