實現這三個功能的踩坑記錄。
1. 需求
在Vue中,有一個input, 雙擊時編輯文本,點擊該input節點外的其他地方,則取消編輯。
那么這里有三個要實現的地方
第一是雙擊顯示編輯框。
第二是自動聚焦點擊的顯示框。
第三是點擊編輯框外的地方,隱藏編輯框。
一二點都是在startPipeLineNameEdit這個method中去實現。
2. 實現雙擊顯示編輯框
思路: 使用兩個span包含雙擊前和雙擊后的代碼,用isEditingPipeLineName這個變量去控制顯示與否。(PipeLineName與我寫的當前組件有關)。
然后綁定一個雙擊時的事件@dblclick="startPipeLineNameEdit"。
父組件BoardArea大致代碼
//PipeLine是子組件,可見可以有很多個子組件實例,因為v-for了一個數組
<PipeLine
v-for="pipeLine in wrappedPipeLineList"
:pipeLine="pipeLine"
class="pipe-line-item"
:key="pipeLine.id"
/>
子組件PipeLine大致代碼
<span v-show="!isEditingPipeLineName">
..未雙擊前
<span @dblclick="startPipeLineNameEdit"></span>
<span></span>
</span>
<span v-show="isEditingPipeLineName" v-model="editPipeLineName">
...雙擊后
<input class="edit-pipeline"...>
<button ...>save</button>
</span>
3. 實現編輯框自動聚焦。
方案一: 手動操作DOM(不建議,不符合Vue思想)
方案二: 自定義指令,無效。加入TODO,日后研究
方案三: autofocus,無效。加入TODO。
思路:操作DOM,找出那個DOM節點,然后focus。初學Vue,也想不到其他辦法了。其實在Vue中自行操作DOM節點不好,因為Vue是數據驅動的,是自行更新DOM。
startPipeLineNameEdit() {
this.isEditingPipeLineName = true;
let edit_pipeline = document.querySelector('.edit-pipeline');
edit_pipeline.focus();
},
問題1 死活不能focus。
Google后,發現https://forum.vuejs.org/t/setting-focus-to-textarea-not-working/17891。
原來Vue有一個DOM更新周期,可以用$nextTick立即觸發。
startPipeLineNameEdit() {
this.isEditingPipeLineName = true;
this.$nextTick(() => {
let edit_pipeline = document.querySelector('.edit-pipeline');
edit_pipeline.focus();
}
},
問題2 只能focus第一個pipeline
原因:
解決辦法:改成querySelectorAll然后遍歷好了
startPipeLineNameEdit() {
this.isEditingPipeLineName = true;
this.$nextTick(() => {
let edit_pipelines = document.querySelectorAll('.edit-pipeline');
edit_pipelines.forEach((element) => {
element.focus();
})
});
},
4. 實現點擊編輯框外的地方,隱藏編輯框
方法1 首先想到的是“點擊外面”,然后google: "vue click away", "vue click outside"等關鍵字,找到https://stackoverflow.com/questions/36170425/detect-click-outside-element。
里面有自定義vue指令的,也有兩個輪子。選用其中一個輪子vue-clickaway。
// 按文檔上開整
<input class="edit-pipeline" type="text" v-model="editPipeLineName" v-on-clickaway="away">
away() {
console.log('clicked away');
this.isEditingPipeLineName = false;
},
方法1出現的問題(還沒解決有TODO)
性能損耗嚴重: 如果有n個Pipeline, 則每次會觸發n次這個函數。如果這個函數里面有密集計算(例如加個循環加法),導致非常卡。
棄用這個輪子,可能這個輪子不適合去實現這個功能。
還有個原生和jQuery的“點擊外面”的方法,現在功力不行,加入TODO。
方法2 監聽blur事件
得益於自動聚焦(focus),那么我可以監聽focus的相反事件blur。
<input class="edit-pipeline" type="text" v-model="editPipeLineName" @blur="away">
4. 問題又出現了,要解決blur和click沖突問題
原因應該是把邏輯寫在blur里面不對。
方案一: 延遲blur函數里面的邏輯。可以用lodash里面的debounce或者直接在blur執行的回調函數里setTimeout(我這里采用這一種最簡單的方案,延遲100毫秒)
方案二: 改為mousedown。用戶體驗不好。
總結
應該有其他優雅的實現方法,加入TODO。