原文鏈接:https://ssshooter.com/2019-10-16-dont-need-emit-on/
在此之前,子組件到父組件的傳遞事件我一般還是使用 $emit
和 $on
,因爲這個操作理解起來並不難,代碼一般也挺清晰。
不過今天遇到這麼個情況 ——
<div class="button-group">
<button @click="item.reply = !item.reply">
{{item.reply?'取消回覆':'回覆'}}
</button>
<button @click="item.editing = !item.editing">
{{item.editing?'取消修改':'修改'}}
</button>
<button @click="removeComment(item.id)">刪除</button>
</div>
<CommentInput
v-if="item.reply"
@submit="item.reply = false"
:lxid="lxid"
:parentId="item.id"
/>
這是一個評論組件的一部分,button-group
是回覆、修改、刪除 3 個按鈕,點擊回覆的話下面的 CommentInput
組件會顯示。本來想着在那裏操作就在哪裏取消,但是寫完了,產品大人一看,表示不行,按鈕不能在上面,應該統一放在評論內容和輸入框的下方,不妥協。
心想又要加 $emit
和 $on
雖然麻煩,但不是難事,不過 CommentInput
本來還會複用到其他地方,只有這裏需要“取消回覆”功能,這又要做一層判斷,爲了代碼簡潔這個實現還要好好想想。結果靈感就來了 —— 使用 slot
。
<div class="button-group">
<button @click="replyToggle(item)">回覆</button>
<button
v-if="loginInfo.operatorname === item.authorName"
@click="editToggle(item)"
>
{{item.editing?'取消修改':'修改'}}
</button>
<button
v-if="loginInfo.operatorname === item.authorName"
@click="removeComment(item.id)"
>
刪除
</button>
</div>
<CommentInput
v-if="item.reply"
@submit="item.reply = false"
:lxid="lxid"
:parentId="parentId||item.id"
>
<div class="button-group">
<button @click="replyToggle(item)">取消回覆</button>
</div>
</CommentInput>
slot
本身還是很常用的,只是第一次主動意識到使用 slot
可以顯著解決事件傳遞問題。直接把取消回覆按鈕用 slot
嵌入 CommentInput
,直接使用父組件的 replyToggle
方法,免去重新寫 $emit
和 $on
的麻煩,順便還解決了其他地方不需要“取消回覆”的問題,十分有效!
其實感覺 slot 就像一個閉包,帶上了父組件的一切,棲身於子組件。
希望這個分享能給大家一點靈感
PS: 突然想起我坑了一萬年的博客評論組件現在依然還坑着……