🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[toc] >[success] # v-on 知识点 1. 用`v-on`指令监听 DOM 事件,`v-on`中要处理的逻辑比较复杂,因此不支持直接在`v-on`中直接写js代码,例如下面直接使用alert 方法,如果这么写必须是在`vue`实例对象的`method`中有定义alter方法才行,否则不支js 自带一些默认方法直接调用 ~~~html <button v-on:click="alert('a')">v-on按钮</button> ~~~ 2. 事件处理器的值可以有两种表现形式,**内联事件处理器** 和 **方法事件处理器** * **内联事件处理器**,事件被触发时执行的内联 JavaScript 语句(最通俗理解,调用方法时候有括号,直接使用以声明属性)实际上是将其执行的是一段 `js `代码 ~~~html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <div id="app"> {{count}} <button @click="count++">内联</button> <button @click="add()">内联</button> <button @click="addStep(2)">内联</button> <button @click="addStep(2);add()">内联</button> </div> <!-- 通过cdn 引入 --> <script src="https://unpkg.com/vue@next"></script> <script> const app = Vue.createApp({ data() { return { count: 1, } }, methods: { add() { this.count++ }, addStep(num) { this.count += num }, }, }) app.mount('#app') </script> </body> </html> ~~~ * **方法事件处理器**,一个指向组件上定义的方法的属性名或是路径(简单理解直接方法名字) ~~~html <!-- `greet` 是上面定义过的方法名 --> <button @click="greet">Greet</button> ~~~ ~~~ data() { return { name: 'Vue.js' } }, methods: { greet(event) { // 方法中的 `this` 指向当前活跃的组件实例 alert(`Hello ${this.name}!`) // `event` 是 DOM 原生事件 if (event) { alert(event.target.tagName) } } } ~~~ 二者检测形式:` v-on` 的值是否是合法的 `JavaScript `标识符或属性访问路径来断定是何种形式的事件处理器。举例来说,**foo、foo.bar 和 foo['bar'] 会被视为方法事件处理器**,而 **foo() 和 count++ 会被视为内联事件处理器** 。 >[info] ## 常见使用 ~~~html <!-- 动态事件 --> <button v-on:[event]="doThis"></button> <!-- 动态事件缩写 --> <button @[event]="doThis"></button> <!-- 对象语法 --> <button v-on="{ mousedown: doThis, mouseup: doThat }"></button> <!-- 一个事件绑定多个方法 --> <button @click="one($event), two($event)">Submit</button> ~~~ >[danger] ##### 关于event * 在正常使用js 绑定事件时候,都会获取到`event`对象 ~~~ <button>获取evnet</button> document.querySelector('button').onclick = function (event) { console.log(event) // 打印出 event 对象 } ~~~ * 在 `vue` 中使用 也可以将么`event`对象会传递进来,在**内联事件处理器**和**方法事件处理器** 传递形式不同 ~~~ html <!-- 1.默认传递event对象 --> <button @click="btn1Click">按钮1</button> <!-- 2.自己的参数和event对象 --> <!-- 在模板中想要明确的获取event对象: $event --> <button @click="btn3Click('zzz', $event)">按钮3</button> ~~~ ~~~ methods: { // 1.默认参数: event对象 // 总结: 如果在绑定事件的时候, 没有传递任何的参数, 那么event对象会被默认传递进来 btn1Click(event) { console.log('btn1Click:', event) }, // 2.明确参数+event对象 btn3Click(name, event) { console.log('btn3Click:', name, event) }, }, ~~~ >[info] ## 事件修饰符 1. `.stop` - 调用 `event.stopPropagation()` 阻止事件冒泡 2. `.prevent` - 调用 `event.preventDefault()`。阻止默认事件从里到外 3. `.capture` - 添加事件侦听器时使用 `capture `模式。实现捕获触发事件的机制从外到里 4. `.self` - 只当事件是从侦听器绑定的元素本身触发时才触发回调。只会阻止自己身上的行为 5. `.{keyAlias}` - 仅当事件是从特定键触发时才触发回调。(键盘简写) 6. `.once` - 只触发一次回调。 7. `.left` - 只当点击鼠标左键时触发。 8. `.right` - 只当点击鼠标右键时触发。 9. `.middle` - 只当点击鼠标中键时触发。 10. `.passive` - { passive: true } 模式添加侦听器 >[danger] ##### 阻止事件冒泡 -- stop 1. 多个元素嵌套,有层次关系,这些元素都注册了相同的事件,如果里面的元素事件触发了,外面的元素的该事件自动的触发了,注意相同事件(都是点击事件,中点击叫做事件) 2. 事件冒泡从里向外 3. 阻止事件冒泡使用stop ~~~ html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <style> .inner { width: 200px; height: 200px; background-color: darkseagreen; } </style> </head> <body> <div id="app"> <div class="inner" id="app" @click="divClick"> <input type="button" value="点击" @click.stop="inputClick" /> </div> </div> <!-- 引入vue cdn --> <script src="https://unpkg.com/vue@next"></script> <script> const vm = Vue.createApp({ methods: { divClick() { console.log('最外层div') }, inputClick() { console.log('最内层div') }, }, }).mount('#app') </script> </body> </html> ~~~ * 点击按钮效果: ~~~ 最内层div ~~~ * 如果没有增加stop ~~~ 最内层div 最外层div ~~~ >[danger] ##### 实现捕获触发事件的机制 -- capture 1. 冒泡是从向外依次触发,使用`capture`,就变成了从 **先显示外面,在显示里面** ~~~ html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <style> .inner { width: 200px; height: 200px; background-color: darkseagreen; } </style> </head> <body> <div id="app"> <div class="inner" id="app" @click.capture="divClick"> <input type="button" value="点击" @click="inputClick" /> </div> </div> <!-- 引入vue cdn --> <script src="https://unpkg.com/vue@next"></script> <script> const vm = Vue.createApp({ methods: { divClick() { console.log('最外层div') }, inputClick() { console.log('最内层div') }, }, }).mount('#app') </script> </body> </html> ~~~ * 打印结果 ~~~ 最外层div 最内层div ~~~ >[danger] ##### .self -- 组织自己的事件行为 1. 只会阻止自己身上的行为 ,像下面的案例当有多层嵌套的时候,只会阻止有self 冒泡行为 2. 官网的第一个提示:使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用` @click.prevent.self`会阻止元素本身及其子元素的点击的默认行为,而 `@click.self.prevent` 只会阻止对元素自身的点击的默认行为。 ~~~ html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <style> .inner { width: 200px; height: 200px; background-color: darkseagreen; } </style> </head> <body> <div id="app"> <div class="outer" @click="div2Handler"> <div class="inner" @click.self="div1Handler"> <input type="button" value="戳他" @click="btnHandler" /> </div> </div> </div> <!-- 引入vue cdn --> <script src="https://unpkg.com/vue@next"></script> <script> const vm = Vue.createApp({ methods: { div1Handler() { console.log('这是触发了 inner div 的点击事件') }, btnHandler() { console.log('这是触发了 btn 按钮 的点击事件') }, div2Handler() { console.log('这是触发了 outer div 的点击事件') }, }, }).mount('#app') </script> </body> </html> ~~~ * 打印结果 ~~~ 这是触发了 btn 按钮 的点击事件 这是触发了 outer div 的点击事件 ~~~ >[danger] ##### 阻止默认事件 -- prevent 1. 例如a标签默认事件就是点击跳转页面,为了**阻止a标签的默认事件触发我们绑定的事件**,可以使用prevent 2. 图片的默认事件**禁止拖拽**,如果想给图片设置拖拽效果的话记得做阻止默认行为 ~~~ html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <style></style> </head> <body> <div id="app"> <a href="www.baidu.com" @click.prevent.once="linkClick">百度</a> </div> <!-- 引入vue cdn --> <script src="https://unpkg.com/vue@next"></script> <script> const vm = Vue.createApp({ methods: { linkClick: function () { alert(1) }, }, }).mount('#app') </script> </body> </html> ~~~ * 运行的效果 ~~~ 1.a标签不会页面跳转,反而点击后会弹出弹窗显示1,当下次点击时候会跳转a 标签地址 ~~~ >[danger] ##### 阻止默认事件 -- passive 1 . `passive`主要用在移动端的scroll事件,来提高浏览器响应速度,提升用户体验。因为passive=true等于提前告诉了浏览器,`touchstart`和`touchmove`不会阻止默认事件,手刚开始触摸,浏览器就可以立刻给与响应;否则,手触摸屏幕了,但要等待`touchstart`和`touchmove`的结果,多了这一步,响应时间就长了,用户体验也就差了。 ~~~ <!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发, --> <!-- 而不会等待 `onScroll` 完成, --> <!-- 以防止其中包含 `event.preventDefault()` 的情况 --> <div @scroll.passive="onScroll">...</div> ~~~ >[danger] ##### 特定按键 .{keyAlias} [按键别名](https://v3.cn.vuejs.org/guide/events.html#%E6%8C%89%E9%94%AE%E5%88%AB%E5%90%8D) >[info] ## 官方文档位置 [官方文档](https://cn.vuejs.org/guide/essentials/event-handling.html#listening-to-events) [官网事件地址](https://v3.cn.vuejs.org/api/directives.html#v-on)