• 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多的时间。如果你有更好的想法,希望能跟我留言~

  • 相关阅读:
    C# DateTime
    C# const static readonly
    HTML div+CSS
    javaScript 正则表达式验证
    前期绑定和后期绑定
    如何应对大数据量高并发访问问题
    数据库优化之:SQL语句优化之二
    银河系漫游指南 图标
    [转] 花3分钟时间来关闭你电脑上没用的服务
    Devdays 2006 China 微软开发者日
  • 原文地址:https://www.cnblogs.com/webhmy/p/14638319.html
Copyright © 2020-2023  润新知