cke點擊時初始化編輯器後光標恢復的方法

業務場景

1、使用了CKEDITOR編輯器
2、文本是使用contenteditable="true"的div容器
3、點擊文本時才初始化編輯器
4、問題:編輯器初始化後光標會重置到開始處,如何將光標重置到點擊處

解決方案

1、在點擊文本的時候,在點擊文本的時候,獲取range信息和 endContainerendOffset;

      try {
          range = window.getSelection().getRangeAt(0);
          var endContainer = range.endContainer;
          var endOffset = range.endOffset;         
        } catch (e) {
          console.log(e);
        }

2、坑:直接點擊圖片,無法獲取到range,需要把圖片加入到range中;

       // 把圖片加進選區
        if (e.target.nodeName === 'IMG') {
          var range2 = document.createRange();
          var selectTion = window.getSelection();
          selectTion.removeAllRanges();
          range2.selectNode(e.target);
          selectTion.addRange(range2);          
        }

3、在初始化編輯器後,在它的instanceReady方法回調中進行光標恢復操作

CKEDITOR.instances[id].once('instanceReady', () => {
 ...          
});

聽起來很美好,對不對,但是在實際操作中發現,之前存儲的endContainer已經被替換成新的range信息了。如何獲取我們原來存儲的endContainer呢?博主試了深拷貝,淺拷貝都不行,於是才用了遍歷尋找的方法~~~

4、找到原來的endContainer 的方法

// 獲取新的endContainer
  getEndContainer(endContainer, tag, endContainer2) {
    let childNodes = self.getAllChildNodes(tag);
    if (childNodes && childNodes.length > 0) {
      for (let i = 0, len = childNodes.length; i < len; i++) {
        let item = childNodes[i];
        if (
          (item.data && item.data === endContainer.data) ||
          (item.wholeText && item.wholeText === endContainer.wholeText) ||
          (item.innerHTML && item.innerHTML === endContainer.innerHTML)
        ) {
          // 爲了避免有重複片段,必須其父親也要相同,我這裏的每行父級元素都有類名cut-check
          let $endContainerParent = $(endContainer).hasClass('cut-check') ? $(endContainer) : $(endContainer).parents('.cut-check');
          let $itemParent = $(item).hasClass('cut-check') ? $(item) : $(item).parents('.cut-check');

          if ($endContainerParent.attr('data-value') === $itemParent.attr('data-value')) {
            endContainer2 = item;
            break;
          }
        }
      }
    }
    return endContainer2;
  }

5、恢復光標:這裏需要再加個延遲,不然光標還沒有初始化到開頭處

CKEDITOR.instances[id].once('instanceReady', () => {
            setTimeout(() => {
              try {
                var newRange = document.createRange();
                var set = window.getSelection();

                // 找到與 endContainer 一樣的節點
                let endContainer2 = null;
                endContainer2 = self.getEndContainer(endContainer, tag, endContainer2);
                newRange.setEnd(endContainer2, endOffset);
                newRange.collapse(false);
                set.removeAllRanges();
                set.addRange(newRange);    
                
              } catch (e) {
                console.log(e)
              }              
            }, 500)
          });

6、坑:到這裏,我們已經實現了光標恢復,但是會發現光標會現在起始處閃一下,再閃到我們點擊處。作爲有強迫症的前端肯定不能容忍這種操作了,這個我們使用樣式就可以處理了:在開始點擊的時候給目標div添加一個隱藏光標的樣式,然後恢復光標的時候移除即可。

.hide-caret {
  caret-color: transparent;
}

讓我們再看下效果:

結束語

至此,完成了我們的業務需求,當然第一次點擊的時候會有不可見的1-2s的延遲,但是沒辦法,編輯器的初始化就需要1s多的時間。如果你有更好的想法,希望能跟我留言~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章