事件代理,冒泡,原生事件,el-radio,伪元素

306 阅读2分钟

起初,是在工作中遇到这样一段代码

// 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();
    }

最后,修复成功。 由于这次记录花了较长时间,记录一下,加深印象,也为以后遇到同样的问题,可以当作参考手册来翻阅。也希望能对其他的朋友有所帮助!