美文网首页
@ 功能 JS 实现原理详解

@ 功能 JS 实现原理详解

作者: 懒懒猫 | 来源:发表于2022-02-16 10:17 被阅读0次

    来源于:Web前端开发之@ 功能 JS 实现原理详解 http://www.javashuo.com/article/p-bcfyqyay-y.html

    监听是否选中@对象,重置编辑框内容

    1.取以前保留先来的信息
    2.删除 @ 符号
    3.生成需要显示的内容,一个 span
    4.将生成内容打包放在 Fragment 中
    5.将 Fragment 中的内容放入 range 中,并将光标放在空格之后
    6.成功选人后让输入框获取焦点

        setEditor: {
          handler: function (newVal, oldVal) {
            if (newVal) {
              this.paramsFlag = false
    
              // 获取以前保留先来的信息。
              this.editor.cmd.do('insertHTML', ' ') //在选中@对象后生成一个空格,wangeditor组件内功能,若用其他组件,可参考注释内容
              var selection = this.selection
              var range = this.range
              var textNode = range.startContainer
              var paramsLen = this.params.length // 获取@参数的长度
    
              // 删除 @ 符号。
              range.setStart(textNode, range.endOffset - 1)
              range.setEnd(textNode, range.endOffset + paramsLen)
              range.deleteContents()
    
              // 生成需要显示的内容,一个 span 
              var spanNode1 = document.createElement('span')
              spanNode1.className = 'at-text'
              spanNode1.innerHTML = this.setEditorCon.data
            
              // var spanNode2 = document.createElement('span')  // 在@回乡后生成一个空格
              // spanNode2.innerHTML = ' '
    
              // 将生成内容打包放在 Fragment 中
              var frag = document.createDocumentFragment()
              frag.appendChild(spanNode1)
              // 并获取生成内容的最后一个节点,也就是空格。
              // var node, lastNode
              // while ((node = spanNode2.firstChild)) {
              //   lastNode = frag.appendChild(node)
              // }
    
              // 将 Fragment 中的内容放入 range 中,并将光标放在空格之后。
              range.insertNode(frag)
              // selection.extend(lastNode, 1)
              // 成功选人后让输入框获取焦点
              selection.collapseToEnd()
            }
          },
          deep: true
        }
    

    获取@参数,显示@列表,在onchange里执行

    1.按下了@键,保存按下@时的光标信息
    2.获取当前文本。 有@时,获取@参数,展示@列表;没有有@时,纯文本展示。

                    var params
                    if (this.isKeySelect) {
                      //  按下了@键,保存按下@时的光标信息
                      var selection = window.getSelection()
                      this.selection = selection
                      this.range = selection.getRangeAt(0)
                      // 是否有@参数
                      this.count = 1
                      this.paramsFlag = true
                    }
                    if (this.paramsFlag) {
                   // 获取当前文本
                      var textNode = this.range.startContainer
                      var text = textNode.data
                      if (text.lastIndexOf('@') !== -1) {
                       // 有@时,获取@参数,展示@列表
                        var newIndex = text.lastIndexOf('@')
                        var textLen = text.length
                        var difference
                        if (this.count) {
                          if (this.count === 1) {
                            this.lastTextLen = 0
                          }
                          if (this.lastTextLen) {
                            difference = Math.abs(textLen - this.lastTextLen)
                            if (textLen > this.lastTextLen) {
                              if (difference > 1) {
                                this.count = this.count + difference
                              } else {
                                this.count++
                              }
                            } else {
                              this.count--
                            }
                          } else {
                            this.count++
                          }
                          this.lastTextLen = textLen
                          if (this.count === 2) {
                            params = ''
                          } else {
                            params = text.slice(newIndex + 1, newIndex + this.count - 1)
                          }
                        }
                        this.params = params   // 存储@参数
                        this.setSecelct(editorContentObj, params)   // 获取@列表
                      } else {
                        this.paramsFlag = false
                        // 没有有@时,纯文本展示
                        editorContentObj.editorContent = this.html
                        editorContentObj.isSetId = this.isSelectId
                        // 更新@列表为空,未被选中,发送消息
                        this.getSelNull(editorContentObj)
                      }
                    }
    

    执行鼠标点击事件,键盘事件

    1.光标点击时,@列表不展示
    2.按下键盘时触发,

     mounted () {
        // 光标点击时,@列表不展示
        var wEtext = document.querySelector('.w-e-text') //获取包含内容的div
        var obj = this
        wEtext.onclick = function (e) {
          obj.$emit('getSelMember', false)     // 不展示@列表
        }
        // 按下键盘时触发
        this.keyHand()
      },
    

    键盘事件

    1.按下enter键发送
    2.按下@键保存变量为true,执行后续操作;
    3.按下删除键,删除@xx整体

    删除逻辑

    a :因为在建立时默认会在 @xxx 后添加一个空格,
    因此当得知光标位于 @xxx 以后的一个第一个字符后并按下删除按钮时,
    应该将光标前的 @xxx 给删除
    b :当光标位于 @xxx 中间时,按下删除按钮时应该将整个 @xxx 给删除。

    // 按下enter键后的处理
        keyHand () {
          var obj = this
          var wText = document.querySelector('.w-e-text')
          this.$nextTick(() => {
            wText.onkeydown = function (e) {
                // 按下了enter键发送消息,阻止浏览器默认换行操作
              if (e.keyCode === 13) {
                obj.$emit('getKeySend')
                e.preventDefault() // 阻止浏览器默认换行操作
                return false
              }
                // 按下了@键
              if (e.code === 'Digit2' && e.shiftKey) {
                obj.isKeySelect = true
              } else {
                obj.isKeySelect = false
                 // 按下了删除键
                if (e.code === 'Backspace') {
                  var wTextP = document.querySelector('.w-e-text p')
                  var range = obj.selection.getRangeAt(0)
                  var removeNode = null
                    // 删除为光标前@xx的空格时
                  if (range.startOffset <= 1 && range.startContainer.parentElement.className !== 'at-text') {
                    removeNode = range.startContainer.previousElementSibling
                  }
                   // 删除为光标前@xxx 中间时
                  if (range.startContainer.parentElement.className === 'at-text') {
                    removeNode = range.startContainer.parentElement
                  }
                  if (removeNode) {
                  // 删除子span@标签
                    var removeCon = removeNode.innerText
                    wTextP.removeChild(removeNode)
                    // 更新@id
                    obj.isSelectList.forEach((item, index) => {
                      if (item.data === removeCon) {
                        obj.isSelectList.splice(index, 1)
                        obj.isSelectId.splice(index, 1)
                      }
                    })
                  }
                }
              }
            }
          })
        }
    

    相关文章

      网友评论

          本文标题:@ 功能 JS 实现原理详解

          本文链接:https://www.haomeiwen.com/subject/jmijlrtx.html