在寫自定義組件以及引用時,遇到了一個問題,也就是子組件中明明只做了一次 click 的 $emit 操作,卻在父組件中觸發了兩次事件函數。
之后,在網上找了很多方案。
有提及通過 .stop 阻止事件冒泡的方案,但通過多次測試,並沒有實質效果。
也有一個是通過 .once 的方案,但是很顯然,這個方案並不符合需求。這個方案會使得按鈕組件變成一次性觸發,不可重復操作。
之后,又找到了一個“曲線救國”的方案,也就是通過 setTimeout 的方式,讓同一個事件函數在一定時間內只能被觸發一次,避免二次觸發。雖然,這個方案,確實解決了問題,但卻在復用性上存在極大的問題,尤其是修改原有引用的源碼時,需要沒處都添加上 setTimeout。所以,這也是不太合理的。
隨后,想到了這個問題的根本原因,並不是 $emit 本身的問題,或者說,兩次觸發 handleClick 函數的,其實是兩個地方,而不是都源自於子組件的 $emit 行為。
實際上,第一次觸發 handleClick 函數的,確系子組件通過 $emit 提交的 click 事件。而另外的一次觸發,則是父組件中,作為一個自定義標簽元素的 <yt-button> 本身。
所以,要避免一次點擊,兩次觸發 handleClick 函數,最簡單的方式,就是在子組件中,把 $emit('click') 的行為去除掉。因為 click 事件,事實上在父級處就已經做了處理,並不需要在子組件中做新的處理。
目前我測試發現:
1、在el-tree類型的子組件使用$emit(‘click‘)傳送事件給父組件時,如果雙方監聽的事件名為node-click時,就會出現觸發兩次的現象,
methods: { handleNodeClick(data, node, el) { this.selectNode = node // console.log(this.selectNodeId, this.idName, node) this.$emit('node-click', data, node, el) // console.log('DydFile this.$emit...') } }
<el-container style="height: calc( 100% - 42px )">
<el-aside style="padding: 20px 20px 0;border-right: 2px solid #EDF2F7;">
<dyd-file width="260px" @node-click="selectLeftTree" />
</el-aside>
<el-container>
2、解決辦法
1)雙方的事件傳遞監聽方法使用其他名稱,不使用node-click,就能實現只觸發一次;
2)或者使用此node-click名稱,在子組件中不使用this.$emit('node-click', data, node, el),也可實現只觸發一次
methods: { handleNodeClick(data, node, el) { this.selectNode = node // console.log(this.selectNodeId, this.idName, node) // this.$emit('node-click', data, node, el) // console.log('DydFile this.$emit...') } }
在子組件中注銷 this.$emit('node-click', data, node, el),父組件仍然監聽次事件名。

node-click 為回調事件,父組件直接監聽
node-click
