@click和@click.native有什么区别,如何阻止第三方组件内部的冒泡

一.@click和@click.native的区别

vue @click.native 原生点击事件:

1,给vue组件绑定事件时候,必须加上native ,不然不会生效(监听根元素的原生事件,使用 .native 修饰符)

2,等同于在子组件中:

子组件内部处理click事件然后向外发送click事件:$emit("click".fn)

不多说看代码:

直接在封装组件上使用@click,看看有什么效果

封装组件wrap-component.vue

xml 复制代码
 <template>
   <button>封装组件的点击事件</button>
 </template>
 ​
 <script>
 export default {
   name: 'wrapComponent'
 }
 </script>
 ​
 <style>
 ​
 </style>
 ​

使用封装组件HomeView.vue

xml 复制代码
 <template>
   <div class="home">
     <h2>父组件</h2>
 ​
     <wrap-component @click="handleClick"></wrap-component>
   </div>
 </template>
 ​
 <script>
 import wrapComponent from '@/components/wrap-component.vue'
 ​
 export default {
   name: 'HomeView',
   components: {
     wrapComponent
   },
   methods: {
     handleClick () {
       console.log('点击了封装组件的按钮')
     }
   }
 }
 </script>
 ​

页面效果

点击按钮,控制台并没有打印内容

当我们给封装组件中的按钮添加点击事件

xml 复制代码
 <template>
   <button @click="handleClick">封装组件的点击事件</button>
 </template>
 ​
 <script>
 export default {
   name: 'wrapComponent',
   methods: {
     handleClick () {
       this.$emit('click')
     }
   }
 }
 </script>
 ​
 <style>
 ​
 </style>

页面效果

发现控制台打印了内容,说明触发了封装组件内部的按钮的点击事件

当我们使用@click.native呢?

封装组件wrap-component.vue

xml 复制代码
 <template>
   <button>封装组件的点击事件</button>
 </template>
 ​
 <script>
 export default {
   name: 'wrapComponent'
 }
 </script>
 ​
 <style>
 ​
 </style>

使用封装组件HomeView.vue

xml 复制代码
 <template>
   <div class="home">
     <h2>父组件</h2>
 ​
     <wrap-component @click.native="handleClick"></wrap-component>
   </div>
 </template>
 ​
 <script>
 import wrapComponent from '@/components/wrap-component.vue'
 ​
 export default {
   name: 'HomeView',
   components: {
     wrapComponent
   },
   methods: {
     handleClick () {
       console.log('点击了封装组件的按钮')
     }
   }
 }
 </script>
 ​

页面效果

也打印了内容,说明与上面通过子组件$emit出来一样。

那可以把@click.native当作是上面$emit的简写吗?

当我们给封装组件添加其他内容呢?

封装组件wrap-component.vue

xml 复制代码
 <template>
   <div>
     <button>封装组件的点击事件</button>
     <ul>
       <li>测试</li>
       <li>测试</li>
       <li>测试</li>
       <li>测试</li>
     </ul>
   </div>
 </template>
 ​
 <script>
 export default {
   name: 'wrapComponent',
   methods: {
   }
 }
 </script>
 ​
 <style>
 ​
 </style>
 ​

页面效果:

点击封装组件的任意一个区域都可以打印内容。

说明@click.native并不是通过$emit方式的简写,在只有单个元素点击事件的情况下可以当作是。

native就是把组件变回原生DOM的一种方式,相当于给组件绑定原生事件

特别说明

针对vue-element-ui中的el-button

typescript 复制代码
 //这个库已经在某些地方把原生的click做了处理了,因为不使用native,照常成功
 <el-button type="primary" @click="handleLogin">Sign in</el-button>

二.其他修饰符

在事件处理器中可以使用event.preventDefault()(阻止原生事件), event.stopPropagation()(阻止事件冒泡)。 vue.js为 v-on 提供两个 事件修饰符:.prevent 与 .stop,让html就可以实现这两个功能,不需要再在js中单独写

xml 复制代码
 <!-- 阻止单击事件继续传播 -->
 <a v-on:click.stop="doThis"></a>
 ​
 <!-- 提交事件不再重载页面 -->
 <form v-on:submit.prevent="onSubmit"></form>
 ​
 <!-- 修饰符可以串联 -->
 <a v-on:click.stop.prevent="doThat"></a>
 ​
 <!-- 添加事件监听器时使用事件捕获模式 -->
 <!-- 即元素自身触发的事件先在此处理,然后才交由内部元素进行处理 -->
 <div v-on:click.capture="doThis">...</div>
 ​
 <!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
 <!-- 即事件不是从内部元素触发的 -->
 <div v-on:click.self="doThat">...</div>

使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,

v-on:click.prevent.self 会阻止所有的点击

v-on:click.self.prevent 只会阻止对元素自身的点击

xml 复制代码
 <!-- 点击事件将只会触发一次 -->
 <a v-on:click.once="doThis"></a>
 ​
 <!-- 不像其它只能对原生的 DOM 事件起作用的修饰符,.once 修饰符还能被用到自定义的组件事件上,该处理函数只会触发一次 -->
 <wrap-component @click.native.once="clickTree"></wrap-component>

不像其它只能对原生的 DOM 事件起作用的修饰符,.once 修饰符还能被用到自定义的组件事件上。

Vue 还对应 addEventListener 中的 passive 选项提供了 .passive 修饰符。

xml 复制代码
 <!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
 <!-- 而不会等待 `onScroll` 完成  -->
 <!-- 这其中包含 `event.preventDefault()` 的情况 -->
 <div v-on:scroll.passive="onScroll">...</div>

这个 .passive 修饰符尤其能够提升移动端的性能。

不要把 .passive.prevent 一起使用,因为 .prevent 将会被忽略,同时浏览器可能会向你展示一个警告。请记住,.passive 会告诉浏览器你不想阻止事件的默认行为。

使用@click.native.stop来阻止第三方组件的点击事件

场景

在父组件中有一个点击事件,但是在父组件内部又使用其他三方组件,因为是第三方组件所以不能通过在第三方组件内部通过@click.stop的方式来阻止冒泡。现在希望的情况就是,在点击第三方组件封装的点击事件的时候,不想让其冒泡其父组件,触发父组件的点击事件。

场景代码

父组件HomeView.vue

xml 复制代码
 <template>
   <div class="home" @click="handleParentClick">
     <h2>父组件</h2>
 ​
     <div>
       <wrap-component></wrap-component>
     </div>
   </div>
 </template>
 ​
 <script>
 import wrapComponent from '@/components/wrap-component.vue'
 ​
 export default {
   name: 'HomeView',
   components: {
     wrapComponent
   },
   methods: {
     handleParentClick () {
       console.log('触发了父组件的点击事件')
     }
   }
 }
 </script>
 ​

封装组件wrap-component.vue

xml 复制代码
 <template>
   <div @click="handleSonClick">
     <button>封装组件的点击事件</button>
     <ul>
       <li>测试</li>
       <li>测试</li>
       <li>测试</li>
       <li>测试</li>
     </ul>
   </div>
 </template>
 ​
 <script>
 export default {
   name: 'wrapComponent',
   methods: {
     handleSonClick () {
       console.log('触发了封装组件的点击事件')
     }
   }
 }
 </script>
 ​
 <style>
 ​
 </style>
 ​

页面效果

触发了封装组件的点击事件,也冒泡到了父组件,触发了父组件的点击事件

解决

在第一点的时候,介绍了native的作用,它把组件变回原生DOM的一种方式,相当于给组件绑定原生事件,那我们可以直接在组件上使用@click.native.stop来阻止第三方组件内部点击事件的冒泡吗?

父组件HomeView.vue

xml 复制代码
 <template>
   <div class="home" @click="handleParentClick">
     <h2>父组件</h2>
 ​
     <div>
       <wrap-component @click.native.stop></wrap-component>
     </div>
   </div>
 </template>
 ​
 <script>
 import wrapComponent from '@/components/wrap-component.vue'
 ​
 export default {
   name: 'HomeView',
   components: {
     wrapComponent
   },
   methods: {
     handleParentClick () {
       console.log('触发了父组件的点击事件')
     }
   }
 }
 </script>
 ​

果然是可以的

扩展

一个组件的话可以通过上面描述的方式来解决,如果父组件有多个第三方组件呢,难道要给每个组件添加@click.native.stop吗?如果不闲麻烦的话,当然是可以的。

也有更加简便的方法

父组件HomeView.vue

xml 复制代码
 <template>
   <div class="home" @click="handleParentClick">
     <h2>父组件</h2>
 ​
     <div @click.stop>
       <wrap-component></wrap-component>
       <wrap-demo></wrap-demo>
     </div>
   </div>
 </template>
 ​
 <script>
 import wrapComponent from '@/components/wrap-component.vue'
 import wrapDemo from '@/components/wrap-demo.vue'
 ​
 export default {
   name: 'HomeView',
   components: {
     wrapComponent,
     wrapDemo
   },
   methods: {
     handleParentClick () {
       console.log('触发了父组件的点击事件')
     }
   }
 }
 </script>
 ​

把使用第三方组件统一包裹起来,对其div使用@click.stop来阻止冒泡

总结

  1. @click.native就是把组件变回原生DOM的一种方式,相当于给组件绑定原生点击事件。
  2. 可以通过这个机制来阻止第三方组件内部封装的冒泡
  3. 如果是直接绑定在原生的div之类的元素上的话,是不需要使用.native的,通常只需要用其他几个后缀。
  4. .native是用来阻止原生的dom事件,一般想要阻止组件内原生的dom事件就需要用.native搭配其他后缀来实现
  5. @click.stop阻止组件$emit的click事件
  6. @click.native.stop阻止组件内原生的dom的click事件
相关推荐
ywf12152 小时前
前端的dist包放到后端springboot项目下一起打包
前端·spring boot·后端
恋猫de小郭2 小时前
2026,Android Compose 终于支持 Hot Reload 了,但是收费
android·前端·flutter
hpoenixf8 小时前
2026 年前端面试问什么
前端·面试
还是大剑师兰特8 小时前
Vue3 中的 defineExpose 完全指南
前端·javascript·vue.js
泯泷8 小时前
阶段一:从 0 看懂 JSVMP 架构,先在脑子里搭出一台最小 JSVM
前端·javascript·架构
mengchanmian9 小时前
前端node常用配置
前端
华洛9 小时前
利好打工人,openclaw不是企业提效工具,而是个人助理
前端·javascript·产品经理
xkxnq9 小时前
第六阶段:Vue生态高级整合与优化(第93天)Element Plus进阶:自定义主题(变量覆盖)+ 全局配置与组件按需加载优化
前端·javascript·vue.js
A黄俊辉A10 小时前
vue css中 :global的使用
前端·javascript·vue.js
小码哥_常11 小时前
被EdgeToEdge适配折磨疯了,谁懂!
前端