起初,是在工作中遇到这样一段代码
// html
<div @click="getEntsByIndex(index)">
<el-input v-model="item.name"></el-input>
<el-radio
:disabled="item.id && formData.deployed ? true : false"
:options="relationData"
v-model="item.relation"
></el-radio>
</div>
//js
getEntsByIndex(index) {
this.$emit("getEntsByIndex");
alert('change')
this.$forceUpdate();
},
测试反馈,当点击下面的radio时,会连续两次alert,与期望不符
第一步,根据提示,找到触发的源代码,也就是上面这段
第二步,推测事件发生的原因:由于事件的冒泡机制,导致事件被多次触发。解决方案:阻止子元素事件冒泡
第三步,实施解决方案。这一步里发生了很大的错误。
一开始我去阻止radio的change事件,结果发现,没有任何作用,期间还尝试了prevent事件,以及还原v-model的方式。后来发现radio没有change事件(ps:搞错了组件版本)。
等找对了版本后,阻止它的input事件,却报错了 e.stopPropagation is a not function,原来el-radio文档上的事件,属于自定义事件。
然后我就去找阻止原生事件的方法,尝试了 @input.native.stop @click.native.stop 之后,发现要么是没有作用(前者),要么是radio的值不变了(后者)。
在一阵抓头挠耳之后,决定监听div的click事件。通过日志打印e.target得知,当点击 radio时,确实响应了两次,而input只会响应一次。
radio响应的两次:1。class="el-radio__inner" 上触发的。2。class="el-radio__original"。
于是明白,div上的click并不是监听radio的自定义事件,而是通过事件冒泡代理监听他的原生click事件。而恰巧,div的子元素中input只会响应一次。radio在点击时,由于使用了伪元素,点击区域响应了两次。
理解了他的本意和触发的原理之后。于是在div上的监听事件进行了修改:
<div @click="(e)=>getEntsByIndex(index,e)">
<el-input v-model="item.name"></el-input>
<el-radio
:disabled="item.id && formData.deployed ? true : false"
:options="relationData"
v-model="item.relation"
></el-radio>
</div>
getEntsByIndex(index, e) {
// 只处理子元素上的事件
if (e.currentTarget === e.target) {
return
}
// 排除radio中span元素的click事件
if (e.target.tagName === 'SPAN') {
return
}
this.$emit("getEntsByIndex", index);
this.$forceUpdate();
}
最后,修复成功。 由于这次记录花了较长时间,记录一下,加深印象,也为以后遇到同样的问题,可以当作参考手册来翻阅。也希望能对其他的朋友有所帮助!