# 事件处理

在平常开发中,对 DOM 的操作很常见,然而 Vue 中是虚拟 DOM 不太提倡直接进行原生 DOM 操作,降低性能。在 Vue 中可以使用 v-on 指令来操作 DOM 事件。

# 事件监听

简单示例,计数器:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>syl-vue-test</title>
    <!-- 引入 vue.js -->
    <script src="https://labfile.oss.aliyuncs.com/courses/1262/vue.min.js"></script>
    <style>
      button {
        width: 150px;
        height: 40px;
        border-radius: 10px;
        background: green;
        outline: none;
        color: #fff;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <!-- v-on:click 绑定点击监听 点一次counter累加一次-->
      <button v-on:click="counter+=1">点击</button>
      <p>你点了{{counter}}次</p>
    </div>
    <script>
      var app = new Vue({
        el: "#app",
        data: {
          counter: 0,
        },
      });
    </script>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

试一试你的手速,运行效果:

此处输入图片的描述

# 事件监听处理方法

许多事件处理逻辑会更为复杂,所以直接把 JavaScript 代码写在 v-on 指令中是不可行的。因此 v-on 还可以接收一个需要调用的方法名称。该方法写在 methods 对象中。

# methods 对象中实现方法

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>syl-vue-test</title>
    <!-- 引入 vue.js -->
    <script src="https://labfile.oss.aliyuncs.com/courses/1262/vue.min.js"></script>
    <style>
      button {
        width: 150px;
        height: 40px;
        border-radius: 10px;
        background: green;
        outline: none;
        color: #fff;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <!-- 绑定点击监听 -->
      <button v-on:click="say">点击</button>
    </div>
    <script>
      var app = new Vue({
        el: "#app",
        data: {
          counter: 0,
        },
        methods: {
          //声明事件点击监听 say方法
          say: function (event) {
            //监听事件回调处理 event.type 触发事件类型 说明:`${}`为es6模板字符串,拼接字符串的
            alert(`小楼提醒:你触发了${event.type}事件`);
          },
        },
      });
    </script>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

运行结果:

此处输入图片的描述

# 内联处理器的方法

不同元素触发同一事件或不同事件,调用同用一个方法。

例子:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>syl-vue-test</title>
    <!-- 引入 vue.js -->
    <script src="https://labfile.oss.aliyuncs.com/courses/1262/vue.min.js"></script>
    <style>
      button {
        width: 150px;
        height: 40px;
        border-radius: 10px;
        background: green;
        outline: none;
        color: #fff;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <!-- 绑定点击监听 共用say 方法-->
      <button v-on:click="say('实验楼')">实验楼</button>
      <button v-on:click="say('小楼')">小楼</button>
    </div>
    <script>
      var app = new Vue({
        el: "#app",
        data: {},
        methods: {
          //声明事件点击监听 say方法
          say: function (name) {
            alert(`我是${name}`);
          },
        },
      });
    </script>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

运行结果:

此处输入图片的描述

# 事件修饰符

在事件处理程序中调用 event.preventDefault()event.stopPropagation() 是非常常见的需求,阻止事件冒泡或捕获或者事件默认行为。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。

为了解决这个问题,Vue.js 为 v-on 提供了 事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。

  • .stop(阻止单击事件继续传播)
  • .prevent(阻止事件默认行为)
  • .capture(添加事件监听器时使用事件捕获模式)
  • .self(只当在 event.target 是当前元素自身时触发处理函数 )
  • .once(点击事件将只会触发一次)
  • .passive(滚动事件的默认行为 (即滚动行为) 将会立即触发 )

例子:

.stop 修饰符的应用

未添加 .stop修饰符,事件会触发冒泡行为,点击子元素也会触发父元素的相同事件

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>syl-vue-test</title>
    <!-- 引入 vue.js -->
    <script src="https://labfile.oss.aliyuncs.com/courses/1262/vue.min.js"></script>
    <style>
      /* 居中 */
      .super,
      .child {
        position: absolute;
        top: 0;
        left: 0;
        bottom: 0;
        right: 0;
        margin: auto;
      }
      .super {
        width: 300px;
        height: 300px;
        background: pink;
      }
      .super .child {
        width: 100px;
        height: 100px;
        background: green;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <div class="super" v-on:click="handleClick('super')"><div class="child" v-on:click="handleClick('child')"></div>
      </div>
    </div>
    <script>
      var app = new Vue({
        el: "#app",
        data: {},
        methods: {
          //声明事件点击监听 handleClick
          handleClick: function (name) {
            alert(`我是${name}`);
          },
        },
      });
    </script>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53

运行效果:

此处输入图片的描述

添加修饰符:

<div id="app">
  <div class="super" v-on:click.stop="handleClick('super')"><div class="child" v-on:click.stop="handleClick('child')"></div>
  </div>
</div>
1
2
3
4
5
6

成功阻止事件冒泡,运行结果:

此处输入图片的描述

# 按键修饰符

在监听键盘事件时,我们经常需要检查详细的按键。Vue 允许为 v-on 在监听键盘事件时添加按键修饰符:

.enter
.tab
1
2

.delete (捕获“删除”和“退格”键)

.esc
.space
.up
.down
.left
.right
1
2
3
4
5
6

# .enter 例子

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>syl-vue-test</title>
    <!-- 引入 vue.js -->
    <script src="https://labfile.oss.aliyuncs.com/courses/1262/vue.min.js"></script>
  </head>
  <body>
    <div id="app">
      <input
        type="text"
        v-on:keyup.enter="alert('你按了enter,确定输入完毕?')"
      />
    </div>
    <script>
      var app = new Vue({
        el: "#app",
      });
    </script>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

运行结果:

此处输入图片的描述

# 键码 keycode

使用 keyCode 特征,了解更多键码 (opens new window)

按键 键码
Enter 13
Shift 16
Alt 18
Spacebar 32
Page Up 33
Page Down 34

示例:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>syl-vue-test</title>
    <!-- 引入 vue.js -->
    <script src="https://labfile.oss.aliyuncs.com/courses/1262/vue.min.js"></script>
  </head>
  <body>
    <div id="app">
      <!-- 文本框内按了键码为13的键(enter) 提示 是否输入完毕 -->
      <input type="text" v-on:keyup.13="alert('你按了enter,确定输入完毕?')" />
    </div>
    <script>
      var app = new Vue({
        el: "#app",
      });
    </script>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

运行效果:

此处输入图片的描述

# 系统修饰符

系统特定的组合功能键,如 ctrl+cctrl+v

可以用如下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器。

  • .ctrl
  • .alt
  • .shift
  • .meta

**说明:**在 Mac 系统键盘上,meta 对应 command 键 (⌘)。在 Windows 系统键盘 meta 对应 Windows 徽标键 (⊞)。在 Sun 操作系统键盘上,meta 对应实心宝石键 (◆)。在其他特定键盘上,尤其在 MIT 和 Lisp 机器的键盘、以及其后继产品,比如 Knight 键盘、space-cadet 键盘,meta 被标记为“META”。在 Symbolics 键盘上,meta 被标记为“META”或者“Meta”。

例子,同时鼠标左击和按 ctrl 弹出提示:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>syl-vue-test</title>
    <!-- 引入 vue.js -->
    <script src="https://labfile.oss.aliyuncs.com/courses/1262/vue.min.js"></script>
  </head>
  <body>
    <div id="app">
      <!-- 同时鼠标左击和按ctrl 弹出提示 -->
      <div @click.ctrl="alert('你同时按了鼠标点击和ctrl')">Do something</div>
    </div>
    <script>
      var app = new Vue({
        el: "#app",
      });
    </script>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

运行结果:

此处输入图片的描述

# .exact

.exact 精确按键修饰符,允许你控制由精确的系统修饰符组合触发的事件。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>syl-vue-test</title>
    <!-- 引入 vue.js -->
    <script src="https://labfile.oss.aliyuncs.com/courses/1262/vue.min.js"></script>
  </head>
  <body>
    <div id="app">
      <!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
      <button
        @click.ctrl="alert('你不单单只按了鼠标左键和 Ctrl键,同时按其他键我也可以触发')"
      >
        A
      </button>

      <!-- 有且只有 ctrl键+鼠标左键 被按下的时候才触发 -->
      <button @click.ctrl.exact="alert('你只按ctrl键+鼠标左键,才能触发我')">
        A
      </button>

      <!-- 没有任何系统修饰符被按下的时候才触发 -->
      <button @click.exact="alert('没有按任何系统修饰符')">A</button>
    </div>
    <script>
      var app = new Vue({
        el: "#app",
      });
    </script>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

运行结果:

此处输入图片的描述

# 鼠标按钮修饰符

这些修饰符会限制处理函数仅响应特定的鼠标按钮。

  • .left
  • .right
  • .middle
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>syl-vue-test</title>
    <!-- 引入 vue.js -->
    <script src="https://labfile.oss.aliyuncs.com/courses/1262/vue.min.js"></script>
  </head>
  <body>
    <div id="app">
      <button @click.left="alert('你按了鼠标左击键')">按钮</button>
      <button @click.middle="alert('你按了鼠标滚轮')">按钮</button>
      <button @click.right="alert('你按了鼠标右击键')">按钮</button>
    </div>
    <script>
      var app = new Vue({
        el: "#app",
      });
    </script>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

运行结果:

此处输入图片的描述

# 综合小练习

小游戏(500px),一直鼠标左键,将小球向右移 500px,拼手速的哦:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>syl-vue-test</title>
    <!-- 引入 vue.js -->
    <script src="https://labfile.oss.aliyuncs.com/courses/1262/vue.min.js"></script>
    <style>
      * {
        padding: 0;
        margin: 0;
      }
      #app {
        position: relative;
        width: 500px;
        height: 100px;
        background: black;
      }
      .box {
        position: absolute;
        left: 0;
        top: 0;
        width: 100px;
        height: 100px;
        border-radius: 50%;
        background: red;
        transition: all 0.3s ease-in;
      }
    </style>
  </head>
  <body>
    <div id="app" @click.left="changePosition">
      <div class="box" :style="{left:left+'px'}"></div>
    </div>
    <script>
      var app = new Vue({
        el: "#app",
        data: {
          left: 0,
        },
        methods: {
          changePosition: function () {
            this.left += 25;
            if (this.left >= 500) {
              alert("走了500px了");
              this.left = 0;
            }
          },
        },
      });
    </script>
  </body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

运行效果:

此处输入图片的描述