开发日记之编辑框文本块

120 阅读1分钟

需求

需要一个可编辑的框,其中存在高亮的文字块,所有文字块默认高亮,但我执行删除操作,支持一次删除一个文字块,无论文字块里的字数多少

想法

首先排除用 input,然后问问AI,很棒,给出了关键要素,html 属性 contenteditable ,设置为 true 就代表着元素内部可以编辑内容,然后在元素内部的文字块标记起来——类,属性,元素名等都行。

实现

        <div class="text-edit-container" contenteditable="true" ref="textEditRef">
        123454我是正常字符<span class="pec-text-block">我是高亮</span>woshizhengcdre
        </div>
.text-edit-container {
  outline: 1px solid #e4e7ed;
  border: none;
  padding: 4px 8px;
  height: 240px;
  overflow: auto;

  &:focus {
    outline: 1px solid #409eff;
    border-radius: 2px;
    box-shadow: 2px 2px 12px 0 rgba(0, 0, 0, 0.05);
  }
}
// 高亮元素
.pec-text-block {
  user-select: none;
  cursor: pointer;
  color: #409eff;
  border-radius: 2px;
  background: #e6f7ff;
}

到这里基本就可以实现高亮元素了,然后是删除,删除的话就监听 backspace 按键事件,对光标位置进行判断,代码大致是AI写的,因为 range 这块不太熟

    document.addEventListener('keydown', (event) => {
 if (event.key === 'Backspace') {
        const selection = window.getSelection();
        let blockToRemove = null;
        // 获取需要删除的文字块
        if (selection.rangeCount > 0) {
          const range = selection.getRangeAt(0);
          // 判断 range.startContainer 是否为文本节点
          if (range.startContainer.nodeType === Node.TEXT_NODE) {
            blockToRemove = range.startContainer.parentNode; // 获取父节点
          } else {
            blockToRemove = range.startContainer;
          }
        }
        // 如果光标在一个文字块内部或紧挨着文字块后面,则删除该文字块
        if (blockToRemove && blockToRemove.classList.contains('pec-text-block')) {
          blockToRemove.remove();
          event.preventDefault();
        }
      }
    }
    })
// 记得注销

ok,到这里其实需求差不多结束,接下来就是我对要转高亮块的文字进行特殊处理,就没什么通用性了。

有一个问题

上面的代码高亮的文字块可以编辑,在转换的时候记得给元素加上 contenteditable=false