前情提要
点进这篇文章的小伙伴,应该和博主一样,都是遇到了这种单选框可点击取消的需求。也就只有这种不同寻常的需求,才能让我们发现element框架的缺陷点,话不多说,下面博主来提供一个解决思路。
@click为什么无法触发
其实很简单,在vue中有一条规则,@函数 在自定义组件上使用时,监听的是该组件内部触发的自定义事件方法,所以当我们对组件使用 @click 方法时,就需要组件在内部设置一个 $emit(‘click’) 触发,我们观察下图el-redio的源码,可以发现其未对 click 函数进行绑定
这也就是为什么 el-radio 的click事件无效,就是因为在el-radio组件内部并未监听 click 方法,所以我们的事件失效了。而在 element-ui 组件中大部分组件都对 click 进行处理了,所以出现无法点击的问题,我们第一时间都是怀疑自己哪调错了。
使用 @click.native 触发方式解决
知道了原因,我们选择正确的方法就行,小伙伴们还记得在 vue 中出现的事件修饰符吗,其中一个 vue2 特有的修饰符 .native 刚好满足我们的要求,它的作用就是专门用于监听组件根元素的原生的事件
vue2特有修饰符 | 说明 |
---|---|
.native | 监听组件根元素的原生事件 |
.sync | 双向绑定语法糖 (Vue 3 中已被 v-model 参数替代) |
接着我们把代码中原本的 @click 改为 @click.native 并对元素进行一个判断,因为事件会向下捕获,我们进行一个元素名判断防止误触发,接着进行 setTimeout 延后处理,因为要取消功能必须保证click函数延后触发,不然会和单选框本身的选中逻辑有冲突,调整完成后我们可以尝试一下功能是否生效,
<template><el-radio v-model="select" :label="id" @click.native="select_Click($event,id)" />
</template>
<script>// methods 函数中select_Click(event, value) {// 处理点击元素if (event.target.tagName === 'INPUT') { return }const old = this.select // 记录一个过去值,防止判断出错setTimeout(() => {if (old === value) {this.select = ''}}, 0)}
</script>
完整演示示例
<template><el-radio v-model="select" :label="id" @click.native="select_Click($event,id)" />
</template>
<script>
export default {data() {return {id:1,select:''} },methods:{select_Click(event, value) {// 处理点击元素if (event.target.tagName === 'INPUT') { return }const old = this.select // 记录一个过去值,防止判断出错setTimeout(() => {if (old === value) {this.select = ''// 如果 el-radio 嵌套层级深可增加// this.$forceUpdate()}}, 0)} }
}
</script>