前端实现@功能

思路

  1. 键入 @ 后将选择框显示出来
  2. 点击选择框中的选项时,返回输入框
  3. 输入框中显示 @xxx
  4. 将光标定位在 @xxx 以后
  5. 删除 @xxx 时须要整个 @xxx 一块儿删除

实现

主要是使用 selection 和 range 这两个关于选区对象和光标对象,结合div 的 contenteditable 属性实现

步骤

  1. 先有一个可编辑的 div 元素
<div
    id="atInput"
    contenteditable
    onKeyDown="onKeyDown"
/>
  1. 输入 @ 时,弹出选人的框
    // 输入监听
    function onKeyDown(e) {
    
    
      // ...
      // 如果触发 @
      if (e.code == 'Digit2' && e.shiftKey) {
    
    
        // 打开选择弹窗
        open()
      }
    }

open方法

    // 打开选择框
    function open() {
    
    
      const selection = window.getSelection()
      const range = selection?.getRangeAt(0)
      // 缓存光标所在节点
      state.focusNode = selection.focusNode
      // 缓存光标所在节点位置
      state.focusOffset = selection.focusOffset
      // 显示选择框
      state.visible = true
      // 输入框失去焦点
      let atInput = document.getElementById('atInput')
      atInput.blur()
    }
  1. 选择好人之后, 删除输入的 @ 字符,将选择的人包装成一个标签,放在原先的 @ 的位置且让光标到标签的后方
  function onSelectSubmit(val) {
    
    
    let atInput = document.getElementById('atInput');
    let selection = window.getSelection();
    let range = window.getSelection().getRangeAt(0);
    //选中输入的@符号
    range.setStart(focusNode, focusOffset - 1);
    range.setEnd(focusNode, focusOffset);
    // //删除输入的@符号
    range.deleteContents();

    var spanNode1= document.createElement('span');
    var spanNode2 = document.createElement('span');
    spanNode1.className = 'atFont';
    spanNode1.innerHTML = '@' + s.nickName;
    spanNode1.contentEditable = false;
    spanNode2.innerHTML = '&nbsp;';
    var frag = document.createDocumentFragment(),
      node,
      lastNode;
    frag.appendChild(spanNode1);
    while ((node = spanNode2.firstChild)) {
    
    
      lastNode = frag.appendChild(node);
    }
    range.insertNode(frag);
    selection.extend(lastNode, 1);
    selection.collapseToEnd();
}
  1. 删除, 监听键盘的输入如果输入是 backSpace 则进行删除的操作
 // 输入监听
    function onKeyDown(e) {
    
    
    let atInput = document.getElementById('atInput');
      if (e.code == 'Backspace') {
    
    
        var range = selection.getRangeAt(0);
        var removeNode = null;
        if (range.startOffset <= 1 && range.startContainer.parentElement.className != "atFont")
            removeNode = range.startContainer.previousElementSibling;
        if (range.startContainer.parentElement.className == "atFont")
            removeNode = range.startContainer.parentElement;
        if (removeNode)
            atInput.removeChild(removeNode);
      }
    }

这样,我们的 @ 功能就基本做好了

猜你喜欢

转载自blog.csdn.net/weixin_48845614/article/details/123189804