Vue - 實現雙擊顯示編輯框;自動聚焦點擊的顯示框;點擊編輯框外的地方,隱藏編輯框


實現這三個功能的踩坑記錄。

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。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM