div可编辑,插入元素获取光标,getSelection()对象操作

本身在公司中碰到一个需求是点击按钮,在输入框中展示出按钮的文字。

 查阅网上资料,发现在这方面给出的答案很少,要么就是和我的需求不同,我是用不了,要么就是写的太过复杂,很难优化,因为我看的也是云里雾里的。

所以通过对网上的其他资料研究,自己弄了个汇总的,帮助自己以后再碰到这种需求能够更快的解决。

这里用到的就是一个选区对象和区域对象。window.getSelection()获取选区对象。

Selection 对象表示用户选择的文本范围或插入符号的当前位置。它代表页面中的文本选区,可能横跨多个元素。文本选区由用户拖拽鼠标经过文字而产生。要获取用于检查或修改的 Selection 对象,请调用 window.getSelection()。包括了用户选中的文明范围或光标位置

还有一个区域对象range,window.getSelection().getRangeAt(0),编辑区中的光标位置操作更多还是在这个对象中实现,这是选区中我们选择的范围对象。

如果一上来对这两个对象没有了解的话,还是不建议接着往下看,因为我讲的不是很细,并没有对这两个对象做一个全面的介绍,我的更多细节会在代码中体现。

如果是对这两个对象有了解的话,可以接着往下看,因为我在代码中给了更多的解释,相较于其他的答案更加直观易懂,写的不算很复杂。

<body>
  <!-- 实现一个功能:div变为可编辑,可向编辑框中插入元素和自定义文本,并且可以指定光标位置 -->
  <div class="edit" contenteditable="true" oninput="editInput(event)"></div>
  <!-- 该按钮指定向编辑框中插入元素 -->
  <button class="nodeButton">向编辑框中插入元素</button>
  <br>
  <input type="text" placeholder="请输入文本">
  <!-- 该按钮指定向编辑框中插入自定义文本 -->
  <button class="textButton">向编辑框中输入文本</button>
  <script>
    const div = document.getElementsByClassName("edit")[0]
    const body = document.getElementsByTagName("body")[0]
    const nodeButton = document.getElementsByClassName("nodeButton")[0]
    const textButton = document.getElementsByClassName("textButton")[0]
    const input = document.getElementsByTagName("input")[0]
    const creDOM = document.createElement("div")
    creDOM.innerText = `${div.innerText.length}/100`
    body.appendChild(creDOM)

    // 这一个方法是记录输入字符数的,不需要关心
    function editInput(e) {
      creDOM.innerText = `${div.innerText.length}/100`
    }

    let range = ""
    div.addEventListener("blur", () => {
      // 这一步是保留住edit编辑框中的选区的范围对象。否则失焦后,getSelection()方法返回的选区对象已经不再是编辑框了,已经获取不到编辑框中的范围对象了。
      range = window.getSelection().getRangeAt(0)
    })

    nodeButton.addEventListener("click", () => {
      const span = document.createElement("span")
      span.innerText = "我是一个span元素"
      // 如果在页面刷新再点击编辑框之前就点击了按钮,此时range中并没有选区范围对象
      if (range === "") {
        let selection = window.getSelection()
        selection.selectAllChildren(div) // selectAllChildren把指定元素的所有子元素设为选中区域,并取消之前的选中区域。不包括node节点本身。
        /*
          Selection.collapseToEnd() 方法的作用是取消当前选区,并把光标定位在原选区的最末尾处,如果此时光标所处的位置是可编辑的,且它获得了焦点,则光标会在原地闪烁。
          以上selectAllChildren方法,将div中子节点全部选中,collapseToEnd方法将选中区域取消,并且将光标定位到原区的末尾。
        */
        selection.collapseToEnd()
        range = window.getSelection().getRangeAt(0) // 无论哪一步都需要保存当前编辑框的选区对象
      }
      let sel = window.getSelection()
      range.insertNode(span) // insertNode方法,在range选区开头插入一个节点
      /*
        removeAllRanges方法:删除之前的所有选区。
        这一步的意义:因为当我们点击其他区域时,选区对象已经改变,不再是编辑框中的选区对象,这时候我们接下来的操作都不会符合我们想象中的样子
      */
      sel.removeAllRanges()
      sel.addRange(range) // 这一步就是添加当前区域对象到选区对象中,所以选区对象会再次指向编辑框中的选区,不会出现别的错误操作。
      sel.collapseToEnd()
    })


    // 只要知道如何在div编辑框中插入元素,那么文本节点也是同理的,对照上面的代码修改一点就可以完成需求
    textButton.addEventListener("click", () => {
      // 第一步获取input框中的内容,将其中的内容转为文本节点插入区域对象中
      let inputText = input.value
      const text = document.createTextNode(inputText)
      // 如果在页面刷新再点击编辑框之前就点击了按钮,此时range中并没有选区范围对象
      if (range === "") {
        let selection = window.getSelection()
        selection.selectAllChildren(div) // selectAllChildren把指定元素的所有子元素设为选中区域,并取消之前的选中区域。不包括node节点本身。
        /*
          Selection.collapseToEnd() 方法的作用是取消当前选区,并把光标定位在原选区的最末尾处,如果此时光标所处的位置是可编辑的,且它获得了焦点,则光标会在原地闪烁。
          以上selectAllChildren方法,将div中子节点全部选中,collapseToEnd方法将选中区域取消,并且将光标定位到原区的末尾。
        */
        selection.collapseToEnd()
        range = window.getSelection().getRangeAt(0) // 无论哪一步都需要保存当前编辑框的选区对象
      }
      let sel = window.getSelection()
      range.insertNode(text) // insertNode方法,在range选区开头插入一个节点
      /*
        removeAllRanges方法:删除之前的所有选区。
        这一步的意义:因为当我们点击其他区域时,选区对象已经改变,不再是编辑框中的选区对象,这时候我们接下来的操作都不会符合我们想象中的样子
      */
      sel.removeAllRanges()
      /*
        // 这一步就是添加当前区域对象到选区对象中,所以选区对象会再次指向编辑框中的选区,不会出现别的错误操作。 
         选区对象的指向如果为空,那么它将会由区域对象指定,区域对象只想哪里那么选区对象就指向哪里。这里选区对象为空了,添加编辑框中的区域对象,所以选区就指向了编辑框了。 (这里是我的猜想,我并没有找到直接证据证明是这样的,但是目前的现象好像确实如此)
      */
      sel.addRange(range)
      sel.collapseToEnd()
    })

效果图:

 

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Vue中,可以使用`contenteditable`属性来实现根据光标位置插入元素的功能。下面是一个基本的实现示例: 首先,在Vue组件的模板中,添加一个`div`元素,并设置`contenteditable`属性为true,使其可编辑: ```html <template> <div contenteditable="true" @input="handleInput"></div> </template> ``` 然后,在Vue组件的方法中,定义一个`handleInput`方法来处理输入事件。在该方法中,可以通过`window.getSelection()`获取当前光标的位置,并使用Range对象插入新的元素: ```javascript <script> export default { methods: { handleInput() { const selection = window.getSelection(); const range = selection.getRangeAt(0); // 创建一个新的span元素 const newElement = document.createElement('span'); newElement.textContent = '新元素'; // 插入元素光标位置 range.insertNode(newElement); // 重新设置光标位置 range.setStartAfter(newElement); range.collapse(true); // 清除选区 selection.removeAllRanges(); selection.addRange(range); } } } </script> ``` 在上述示例中,每次在`div`中输入内容时,都会触发`handleInput`方法。该方法获取当前光标位置并创建一个新的`span`元素,然后将其插入光标位置,并重新设置光标位置以便继续输入。最后,清除选区以避免干扰后续输入。 请注意,上述示例仅为演示如何根据光标插入元素,并没有考虑到其他复杂的情况,如光标在不同元素之间移动、选择文本等。实际使用时,可能需要根据具体需求进行适当的扩展和调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值