1️⃣ 监听事件以及事件处理方法

可以用 v-on 指令监听 DOM 事件,并在触发时运行一些 JavaScript 代码。 v-on 调用的方法写在 methods 函数中。

  1. <template>
  2. <div id="app">
  3. <button @click="clickMethod">点击</button>
  4. </div>
  5. </template>
  6. <script>
  7. export default {
  8. name: "App",
  9. data() {
  10. return {};
  11. },
  12. methods: {
  13. clickMethod() {
  14. console.log("被点击了");
  15. },
  16. },
  17. };
  18. </script>

methods 中的函数,也会直接代理给 Vue 实例对象,所以可以直接运行。

  1. const vm = new Vue({
  2. el: "#app",
  3. methods: {
  4. handleClick() {
  5. console.log('v-on:click 被点击');
  6. }
  7. }
  8. });
  9. vm.handleClick() // v-on:click 被点击

除了直接绑定到一个方法,也可以在内联 JavaScript 语句中调用方法传递参数。

  1. <template>
  2. <div id="app">
  3. <button @click="clickMethod('传递参数')">点击</button>
  4. </div>
  5. </template>
  6. <script>
  7. export default {
  8. name: "App",
  9. data() {
  10. return {};
  11. },
  12. methods: {
  13. clickMethod(v) {
  14. console.log(v);
  15. },
  16. },
  17. };
  18. </script>

在内联语句中使用事件对象时,可以利用特殊变量 $event ,$event 代表事件 event。

  1. <template>
  2. <div id="app">
  3. <button @click="clickMethod('传递参数', $event)">点击</button>
  4. </div>
  5. </template>
  6. <script>
  7. export default {
  8. name: "App",
  9. data() {
  10. return {};
  11. },
  12. methods: {
  13. clickMethod(v, event) {
  14. console.log(v, event); // event 就是事件触发对象
  15. },
  16. },
  17. };
  18. </script>

在内联语句中如果不传参数方法中的第一个参数就是事件源对象。

  1. <template>
  2. <div id="app">
  3. <button @click="clickMethod">点击</button>
  4. </div>
  5. </template>
  6. <script>
  7. export default {
  8. name: "App",
  9. data() {
  10. return {};
  11. },
  12. methods: {
  13. clickMethod(e) {
  14. console.log(e);
  15. },
  16. },
  17. };
  18. </script>

可以绑定动态事件,Vue 版本需要 2.6.0+

  1. <template>
  2. <div id="app">
  3. <button @[event]="clickMethod">点击</button>
  4. </div>
  5. </template>
  6. <script>
  7. export default {
  8. name: "App",
  9. data() {
  10. return {
  11. event: "click",
  12. };
  13. },
  14. methods: {
  15. clickMethod(e) {
  16. console.log(e);
  17. },
  18. },
  19. };
  20. </script>

可以不带参数绑定一个对象,Vue 版本需要 2.4.0+

  1. 1. { 事件名:事件执行函数 }
  2. 2. 使用此种方法不支持函数传参&修饰符
  1. <template>
  2. <div id="app">
  3. <!-- 同时绑定了点击和移出事件 -->
  4. <div v-on="{ click: clickA, mouseleave: mouseleaveA }">
  5. click/mouseleave,点击和移出事件
  6. </div>
  7. </div>
  8. </template>
  9. <script>
  10. export default {
  11. name: "App",
  12. data() {
  13. return {
  14. event: "click",
  15. };
  16. },
  17. methods: {
  18. clickA() {
  19. console.log("click");
  20. },
  21. mouseleaveA() {
  22. console.log("mouseleave");
  23. },
  24. },
  25. };
  26. </script>

1️⃣ 事件修饰符

在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。
为了解决这个问题,Vue.js 为 v-on 提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。

2️⃣ .stop - 阻止事件冒泡

  1. <template>
  2. <div id="app">
  3. <div @click="clickA">
  4. <div @click.stop="clickB">点击</div>
  5. </div>
  6. </div>
  7. </template>
  8. <script>
  9. export default {
  10. name: "App",
  11. data() {
  12. return {};
  13. },
  14. methods: {
  15. clickA() {
  16. console.log("clickA"); // 不会触发, 因为 B 被阻止了冒泡
  17. },
  18. clickB() {
  19. console.log("clickB");
  20. },
  21. },
  22. };
  23. </script>

2️⃣ .prevent - 阻止默认事件

添加 .prevent 后 a 标签不会跳转到百度

  1. <template>
  2. <div id="app">
  3. <a href="https://www.baidu.com" @click.prevent>www.baidu.com</a>
  4. </div>
  5. </template>
  6. <script>
  7. export default {
  8. name: "App",
  9. data() {
  10. return {};
  11. },
  12. };
  13. </script>

2️⃣ .capture - 事件捕获模式

  1. <template>
  2. <div id="app">
  3. <div @click.capture="clickA">
  4. <div @click="clickB">点击</div>
  5. </div>
  6. </div>
  7. </template>
  8. <script>
  9. export default {
  10. name: "App",
  11. data() {
  12. return {};
  13. },
  14. methods: {
  15. clickA() {
  16. console.log("clickA"); // 先触发 A
  17. },
  18. clickB() {
  19. console.log("clickB"); // 后触发 B
  20. },
  21. },
  22. };
  23. </script>

2️⃣ .self - 只触发自身事件

只当在 event.target 是当前元素自身时触发处理函数,即事件不是从内部元素触发的

  1. <template>
  2. <div id="app">
  3. <div :style="{ backgroundColor: 'red' }" @click.self="alert('div')">
  4. <button @click="alert('button')">点击</button>
  5. </div>
  6. </div>
  7. </template>
  8. <script>
  9. export default {
  10. name: "App",
  11. data() {
  12. return {};
  13. },
  14. methods: {
  15. alert(str) {
  16. alert(str);
  17. },
  18. },
  19. };
  20. </script>

2️⃣ .once - 只触发一次回调

2.1.4 新增

  1. <template>
  2. <div id="app">
  3. <div @click.once="clickA">点击</div>
  4. </div>
  5. </template>
  6. <script>
  7. export default {
  8. name: "App",
  9. data() {
  10. return {};
  11. },
  12. methods: {
  13. clickA() {
  14. console.log("触发一次");
  15. },
  16. },
  17. };
  18. </script>

2️⃣ .passive - 会告诉浏览器你不想阻止事件的默认行为

2.3.0 新增

Vue 还对应 addEventListener 中的 passive 选项提供了 .passive 修饰符。
这个 .passive 修饰符尤其能够提升移动端的性能。
即使在触发触摸事件时,执行了一个空的函数,也会让页面卡顿。因为浏览器不知道监听器到底会不会阻止默认事件,所以浏览器要等到执行完整个函数后,才能决定是否要滚动页面。passive 事件监听器,允许开发者告诉浏览器,监听器不会阻止默认行为,从而浏览器可以放心大胆的滚动页面,这样可以大幅度提升移动端页面的性能,因为据统计只有 20%的触摸事件会阻止默认事件。
.passive 会告诉浏览器你不想阻止事件的默认行为

2️⃣ .native - 给组件绑定原生事件

.native:在⽗组件中给⼦组件绑定⼀个原⽣的事件,就将⼦组件变成了普通的HTML标签,不加’. native’事件是⽆法触发的。
此时点击页⾯中的按钮⽆任何反应。
添加修饰符,此时点击就会弹窗,可以理解为该修饰符的作⽤就是把⼀个组件转化为⼀个普通的HTML标签,并且该修饰符对普通HTML标签是没有任何作⽤的。

2️⃣ 修饰符的连续调用

  1. <template>
  2. <div id="app" @click="clickB">
  3. <div @click.stop.once="clickA">点击</div>
  4. </div>
  5. </template>
  6. <script>
  7. export default {
  8. name: "App",
  9. data() {
  10. return {};
  11. },
  12. methods: {
  13. clickA() {
  14. console.log("clickA");
  15. },
  16. clickB() {
  17. console.log("clickB");
  18. },
  19. },
  20. };
  21. </script>

1️⃣ 按键修饰符

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

  1. <template>
  2. <div id="app">
  3. <!-- 只有在 key 是 Enter 时调用 keyupA() -->
  4. <input @keyup.enter="keyupA" />
  5. </div>
  6. </template>
  7. <script>
  8. export default {
  9. name: "App",
  10. data() {
  11. return {};
  12. },
  13. methods: {
  14. keyupA() {
  15. console.log("enter 被按下");
  16. },
  17. },
  18. };
  19. </script>

你可以直接将 KeyboardEvent.key 暴露的任意有效按键名转换为 kebab-case 来作为修饰符。

  1. <template>
  2. <div id="app">
  3. <!-- 只有在 key 是 home 时调用 keyupA() -->
  4. <input @keyup.home="keyupA" />
  5. </div>
  6. </template>
  7. <script>
  8. export default {
  9. name: "App",
  10. data() {
  11. return {};
  12. },
  13. methods: {
  14. keyupA() {
  15. console.log("home 被按下");
  16. },
  17. },
  18. };
  19. </script>

在上述示例中,处理函数只会在 $event.key 等于 Home 时被调用。

2️⃣ 按键码

keyCode 的事件用法已经被废弃了并可能不会被最新的浏览器支持。

使用 keyCode 特性也是允许的:

  1. <template>
  2. <div id="app">
  3. <!-- 只有在 key 是 enter 时调用 keyupA() -->
  4. <input @keyup.13="keyupA" />
  5. </div>
  6. </template>
  7. <script>
  8. export default {
  9. name: "App",
  10. data() {
  11. return {};
  12. },
  13. methods: {
  14. keyupA() {
  15. console.log("enter 被按下");
  16. },
  17. },
  18. };
  19. </script>

为了在必要的情况下支持旧浏览器,Vue 提供了绝大多数常用的按键码的别名:

  1. 1. .enter
  2. 2. .tab
  3. 3. .delete ( 捕获“删除”和“退格”键 )
  4. 4. .esc
  5. 5. .space
  6. 6. .up
  7. 7. .down
  8. 8. .left
  9. 9. .right

你还可以通过全局 config.keyCodes 对象自定义按键修饰符别名:
Vue.config.keyCodes.按键名 = 键码

  1. <!-- ********** HTML ********** -->
  2. <body>
  3. <div id="app">
  4. 上:<input @keydown.shang="topKey" type="text">
  5. 下:<input @keydown.xia="bottomKey" type="text">
  6. 左:<input @keydown.zuo="leftKey" type="text">
  7. 右:<input @keydown.you="rightKey" type="text">
  8. </div>
  9. </body>
  10. // ********** JS/VUE **********
  11. // 单个形式
  12. Vue.config.keyCodes.shang = 38;
  13. // 对象形式
  14. Vue.config.keyCodes = {
  15. shang: 38,
  16. xia: 40,
  17. zuo: 37,
  18. you: 39
  19. }
  20. const vm = new Vue({
  21. el: "#app",
  22. methods: {
  23. topKey() {
  24. console.log('shang - 键被按下');
  25. },
  26. bottomKey() {
  27. console.log('xia - 键被按下');
  28. },
  29. leftKey() {
  30. console.log('zuo - 键被按下');
  31. },
  32. rightKey() {
  33. console.log('you - 键被按下');
  34. }
  35. },
  36. });

1️⃣ 系统修饰键

2.1.0 新增

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

  1. 1. .ctrl
  2. 2. .alt
  3. 3. .shift
  4. 4. .meta

请注意修饰键与常规按键不同,在和 keyup 事件一起用时,事件触发时修饰键必须处于按下状态。换句话说,只有在按住 ctrl 的情况下释放其它按键,才能触发 keyup.ctrl。而单单释放 ctrl 也不会触发事件。如果你想要这样的行为,请为 ctrl 换用 keyCode:keyup.17。

  1. <template>
  2. <div id="app">
  3. <!-- 按键组合使用 -->
  4. <input
  5. @keyup.ctrl.c="trigger('Ctrl+c 被触发')"
  6. type="text"
  7. placeholder="Ctrl+c"
  8. />
  9. <!-- 键鼠组合使用 -->
  10. <input
  11. @click.ctrl="trigger('Ctrl 被按下点击鼠标')"
  12. type="text"
  13. placeholder="Ctrl+鼠标click"
  14. />
  15. </div>
  16. </template>
  17. <script>
  18. export default {
  19. name: "App",
  20. data() {
  21. return {};
  22. },
  23. methods: {
  24. trigger(v) {
  25. console.log(v);
  26. },
  27. },
  28. };
  29. </script>

2️⃣ .exact 修饰符

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

  1. <template>
  2. <div id="app">
  3. <!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
  4. <button v-on:click.ctrl="trigger('只要ctrl被按下')">
  5. 当 Ctrl 被按下时触发才能触发点击事件
  6. </button>
  7. <!-- 有且只有 Ctrl 被按下的时候才触发 -->
  8. <button v-on:click.ctrl.exact="trigger('只有ctrl被按下')">
  9. 有且只有 Ctrl 被按下的时候才触发
  10. </button>
  11. <!-- 没有任何系统修饰符被按下的时候才触发 -->
  12. <button v-on:click.exact="trigger('没有任何修饰符被按下')">
  13. 没有任何系统修饰符被按下的时候才触发
  14. </button>
  15. </div>
  16. </template>
  17. <script>
  18. export default {
  19. name: "App",
  20. data() {
  21. return {};
  22. },
  23. methods: {
  24. trigger(str) {
  25. console.log(str);
  26. },
  27. },
  28. };
  29. </script>

2️⃣ 鼠标按钮修饰符

2.2.0 新增

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

  1. <template>
  2. <div id="app">
  3. <!-- 鼠标左键被按下 -->
  4. <button @click.left="trigger('鼠标左键被按下')">鼠标左键被按下</button>
  5. <!-- 鼠标右键被按下 -->
  6. <button @click.right="trigger('鼠标右键被按下')">鼠标右键被按下</button>
  7. <!-- 鼠标滚轮被按下 -->
  8. <button @click.middle="trigger('鼠标滚轮被按下')">鼠标滚轮被按下</button>
  9. </div>
  10. </template>
  11. <script>
  12. export default {
  13. name: "App",
  14. data() {
  15. return {};
  16. },
  17. methods: {
  18. trigger(str) {
  19. console.log(str);
  20. },
  21. },
  22. };
  23. </script>

1️⃣ 为什么在 HTML 中监听事件

你可能注意到这种事件监听的方式违背了关注点分离 (separation of concern) 这个长期以来的优良传统。但不必担心,因为所有的 Vue.js 事件处理方法和表达式都严格绑定在当前视图的 ViewModel 上,它不会导致任何维护上的困难。实际上,使用 v-on 有几个好处:

  1. 1. 扫一眼 HTML 模板便能轻松定位在 JavaScript 代码里对应的方法。
  2. 2. 因为你无须在 JavaScript 里手动绑定事件,你的 ViewModel 代码可以是非常纯粹的逻辑,和 DOM 完全解耦,更易于测试。
  3. 3. 当一个 ViewModel 被销毁时,所有的事件处理器都会自动被删除。你无须担心如何清理它们。