# 事件监听

# 使用

可以用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Title</title>
  </head>

  <body>
    <div id="app">
      <button v-on:click="counter += 1">Add 1</button>
      <p>The button above has been clicked {{ counter }} times.</p>
    </div>

    <script src="/lib/vue.js"></script>
    <script>
      const vm = new Vue({
        el: "#app",
        data: {
          counter: 0,
        },
        methods: {},
      });
    </script>
  </body>
</html>

然而许多事件处理逻辑会更为复杂,所以直接把 JavaScript 代码写在 v-on 指令中是不可行的。因此 v-on 还可以接收一个需要调用的方法名称。有时也需要在内联语句处理器中访问原始的 DOM 事件。可以用特殊变量 $event 把它传入方法

  • 情况1:方法定义时没有参数要接收,调用方法后不加()或添加()都没关系
  • 情况2:方法定义时只想接收一个原生 DOM 事件event参数,调用方法不能加(),默认会传递event参数。若添加了(),将不会传递event参数。也可以添加($event)来传递(不过没必要)。
  • 情况3:方法定义时有自定义参数,则调用方法时必须传递参数(params...)。若还需要event参数,调用时可传递(params,$event)参数

具体查看下面代码:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Title</title>
  </head>

  <body>
    <div id="app">
      <button v-on:click="counter1 += 1">button1</button>
      <p>The button1 above has been clicked {{ counter1 }} times.</p>

      <!-- 不传递参数 -->
      <button @click="increment2">button2</button>
      <p>The button2 above has been clicked {{ counter2 }} times.</p>

      <!-- 传递event -->
      <button @click="increment3">button3</button>
      <p>The button3 above has been clicked {{ counter3 }} times.</p>

      <!-- 传递参数 -->
      <button @click="increment4(5)">button4</button>
      <p>The button4 above has been clicked {{ counter4 }} times.</p>

      <!-- 传递参数+event -->
      <button @click="increment5(5,$event)">button5</button>
      <p>The button5 above has been clicked {{ counter5 }} times.</p>
    </div>

    <script src="/lib/vue.js"></script>
    <script>
      const vm = new Vue({
        el: "#app",
        data: {
          counter1: 0,
          counter2: 0,
          counter3: 0,
          counter4: 0,
          counter5: 0,
        },
        methods: {
          // 不传递参数
          increment2() {
            this.counter2++;
          },
          // 传递event
          increment3(event) {
            this.counter3++;
            // `event` 是原生 DOM 事件
            if (event) {
              console.log(event);
              alert(event.target.tagName);
            }
          },
          // 传递参数
          increment4(num) {
            alert(num);
            this.counter4++;
          },
          // 传递参数+event
          increment5(num, event) {
            alert(num);
            this.counter5++;
            // `event` 是原生 DOM 事件
            if (event) {
              console.log(event);
              alert(event.target.tagName);
            }
          },
        },
      });

      // 也可以用 JavaScript 直接调用方法。一般不用
      // vm.increment2();
    </script>
  </body>
</html>

# 事件修饰符

Vue.js 为 v-on 提供了事件修饰符来处理 DOM 事件细节,如:event.preventDefault() 或 event.stopPropagation()。

Vue.js通过由点.表示的指令后缀来调用修饰符:

  • .stop:停止事件传播,不再派发事件
  • .prevent:停止事件的默认动作
  • .capture
  • .self
  • .once

# .stop

停止事件传播,不再派发事件(冒泡)。底层为 JS 原生调用 event.stopProgatation()

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Title</title>
  </head>

  <body>
    <div id="app">
      .stop
      <div @click="divClick">
        div<button @click.stop="btnClick">btn</button>
      </div>
    </div>

    <script src="/lib/vue.js"></script>
    <script>
      const vm = new Vue({
        el: "#app",
        data: {
          message: "Hello",
        },
        methods: {
          divClick() {
            console.log("divClick");
          },
          btnClick() {
            console.log("btnClick");
          },
        },
      });
    </script>
  </body>
</html>

# .prevent

停止事件的默认动作,如表单提交。底层为 JS 原生调用 event.preventDefault()

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Title</title>
  </head>

  <body>
    <div id="app">
      .prevent
      <form action="http://www.qq.com" method="post" @submit.prevent>
        <!--.prevent-->
        <input type="submit" value="提交" />
      </form>
        
      <form action="http://www.baidu.com" method="post">
        <!--.prevent-->
        <input type="submit" value="提交" @click.prevent="submitClick" />
      </form>
      <hr />
    </div>

    <script src="/lib/vue.js"></script>
    <script>
      const vm = new Vue({
        el: "#app",
        data: {
          message: "Hello",
        },
        methods: {
          submitClick() {
            console.log("submitClick");
          },
        },
      });
    </script>
  </body>
</html>

原生实现

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Title</title>
  </head>

  <body>
    <form action="http://www.qq.com" method="post" onsubmit="return checkForm();">
        <input type="submit" value="提交">
    </form>

   <script>
    function checkForm() {
        return false;
    };
</script>
  </body>
</html>

# .once

事件将只会触发一次

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Title</title>
  </head>

  <body>
    <div id="app">
      .once
      <button @click.once="onceClick">OnceClick</button>
    </div>

    <script src="/lib/vue.js"></script>
    <script>
      const vm = new Vue({
        el: "#app",
        data: {
          message: "Hello",
        },
        methods: {
          onceClick() {
            console.log("onceClick");
          },
        },
      });
    </script>
  </body>
</html>

# 按键修饰符

Vue 允许为 v-on 在监听键盘事件时添加按键修饰符

全部的按键别名:

  • .enter
  • .tab
  • .delete (捕获 "删除" 和 "退格" 键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right
  • .ctrl
  • .alt
  • .shift
  • .meta

# .enter

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Title</title>
  </head>

  <body>
    <div id="app">
      .enter
      <input type="text" @keyup.enter="keyUp" />
    </div>

    <script src="/lib/vue.js"></script>
    <script>
      const vm = new Vue({
        el: "#app",
        data: {
          message: "Hello",
        },
        methods: {
          keyUp() {
            // 未使用.enter前,任何按键keyup都会触发
            console.log("keyUp.按了回车");
          },
        },
      });
    </script>
  </body>
</html>

# .native 组件

监听组件根元素的原生事件