業務場景
1、使用了CKEDITOR編輯器
2、文本是使用contenteditable="true"的div容器
3、點擊文本時才初始化編輯器
4、問題:編輯器初始化後光標會重置到開始處,如何將光標重置到點擊處
解決方案
1、在點擊文本的時候,在點擊文本的時候,獲取range
信息和 endContainer
與endOffset
;
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多的時間。如果你有更好的想法,希望能跟我留言~