1.获取光标位置

<html>

<head>
  <title>光标测试</title>
  <style>
    p {
      display: flex;
      flex-direction: row;
    }

    .btn {
      height: 24px;
      margin: 0 10px;
    }

    .edit-div {
      display: inline-block;
      width: 225px;
      border: 1px solid #decdcd;
    }
  </style>
  <script>

    function getCursortPosition(e) {
      var eleP = e.target.parentNode; //获取父级元素
      var pos = 0;
      if (e.target.nodeName == "DIV") {
        pos = getDivPosition(e.target);
      } else {
        pos = getPosition(e.target);
      }

      var spanEle = (eleP.childNodes)[7];
      spanEle.innerText = pos;
    }

    //可编辑div获取坐标
    const getDivPosition = function (element) {
      var caretOffset = 0;
      var doc = element.ownerDocument || element.document;
      var win = doc.defaultView || doc.parentWindow;
      var sel;
      if (typeof win.getSelection != "undefined") {//谷歌、火狐
        sel = win.getSelection();
        if (sel.rangeCount > 0) {//选中的区域
          var range = win.getSelection().getRangeAt(0);
          var preCaretRange = range.cloneRange();//克隆一个选中区域
          preCaretRange.selectNodeContents(element);//设置选中区域的节点内容为当前节点
          preCaretRange.setEnd(range.endContainer, range.endOffset);  //重置选中区域的结束位置
          caretOffset = preCaretRange.toString().length;
        }
      } else if ((sel = doc.selection) && sel.type != "Control") {//IE
        var textRange = sel.createRange();
        var preCaretTextRange = doc.body.createTextRange();
        preCaretTextRange.moveToElementText(element);
        preCaretTextRange.setEndPoint("EndToEnd", textRange);
        caretOffset = preCaretTextRange.text.length;
      }
      return caretOffset;
    }

    //输入框获取光标
    const getPosition = function (element) {
      let cursorPos = 0;
      if (document.selection) {//IE
        var selectRange = document.selection.createRange();
        selectRange.moveStart('character', -element.value.length);
        cursorPos = selectRange.text.length;
      } else if (element.selectionStart || element.selectionStart == '0') {
        cursorPos = element.selectionStart;
      }
      return cursorPos;
    }
  </script>
</head>

<body>
  <p>
    <label>输入框测试:</label>
    <input type="text" style="width:220px" onclick="getCursortPosition(event);" />
    <span>光标位置:</span>
    <span></span>
  </p>
  <p>
    <label>文本框测试:</label>
    <textarea rows="5" style="width:220px" onclick="getCursortPosition(event);"></textarea>
    <span>光标位置:</span>
    <span></span>
  </p>
  <div>
    <label>可编辑div:</label>
    <div contenteditable="true" class="edit-div" onclick="getCursortPosition(event);"></div>
    <span>光标位置:</span>
    <span></span>
  </div>
</body>

</html>

  

2.设置光标位置

  2.1 设置光标位置input、textarea

<!DOCTYPE html>
<html>

    <head>
        <meta charset="UTF-8">
        <title></title>
    </head>

    <body>
        <input type="text" id="test-input" value="Example" />
        <input type="text" id="test-input2" value="Example" />
    </body>
    <script>
        function setCaretPosition(ctrl, pos) {
            // Modern browsers
            if(ctrl.setSelectionRange) {
                ctrl.focus();
                ctrl.setSelectionRange(pos, pos);

                // IE8 and below
            } else if(ctrl.createTextRange) {
                var range = ctrl.createTextRange();
                range.collapse(true);
                range.moveEnd('character', pos);
                range.moveStart('character', pos);
                range.select();
            }
        }
        var input = document.getElementById('test-input');
        setCaretPosition(input, input.value.length);
    </script>

</html>

  

 2.2 设置光标位置可编辑div

<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <title>在可编辑div中定位和设置光标</title>
    <style>
        #edit {
            height: 500px;
            width: 500px;
            border: 1px solid red;
        }
    </style>
</head>
 
<body>
    <div id="edit" contenteditable></div>
    <input type="text" id="emojiInput">
    <button id="sendEmoji">发送表情</button>
 
    <script>
        // 发送表情的按钮
        var sendEmoji = document.getElementById('sendEmoji');
        // 定义最后光标对象
        var lastEditRange;
 
        // 编辑框点击事件
        document.getElementById('edit').onclick = function () {
            // 获取选定对象
            var selection = getSelection();
            // 设置最后光标对象
            lastEditRange = selection.getRangeAt(0);
        }
 
        // 编辑框按键弹起事件
        document.getElementById('edit').onkeyup = function () {
            // 获取选定对象
            var selection = getSelection();
            // 设置最后光标对象
            lastEditRange = selection.getRangeAt(0);
        }
 
        // 发送表情
        document.getElementById('sendEmoji').onclick = function () {
            // 获取可编辑框
            var edit = document.getElementById('edit');
            // 获取输入框
            var emojiInput = document.getElementById('emojiInput');
            // 编辑框获得焦点
            edit.focus();
 
 
            // 获取选定对象
            var selection = getSelection();
            // 如果保存的有上次的光标对象
            if (lastEditRange) {
                // 清除所有选区
                selection.removeAllRanges();
                // 添加最后光标还原之前的状态
                selection.addRange(lastEditRange);
            }
            // 判断选定对象范围是编辑框还是文本节点,如果是编辑框范围
            if (selection.anchorNode.nodeName != '#text') {
                // 创建表情文本节点进行插入
                var emojiText = document.createTextNode(emojiInput.value);
                // 如果文本框的子元素大于0,则表示有其他元素,则按照位置插入表情节点
                if (edit.childNodes.length > 0) {
                    for (var i = 0; i < edit.childNodes.length; i++) {
                        if (i == selection.anchorOffset) {
                            edit.insertBefore(emojiText, edit.childNodes[i]);
                        }
                    }
                } else {
                    // 否则直接插入一个表情元素
                    edit.appendChild(emojiText);
                }
                // 创建新的光标对象
                var range = document.createRange();
                // 将光标对象的范围界定为新建的表情节点
                range.selectNodeContents(emojiText);
                // 定位光标位置在表情节点的最大长度位置
                range.setStart(emojiText, emojiText.length);
 
                // 将选区折叠为一个光标
                range.collapse(true);
                // 清除所有光标对象
                selection.removeAllRanges();
                // 添加新的光标对象
                selection.addRange(range);
                // 如果是文本节点
            } else {
                // 获取光标对象
                var range = selection.getRangeAt(0);
                // 获取光标对象的范围界定对象,一般就是textNode对象
                var textNode = range.startContainer;
                // 获取光标位置
                var rangeStartOffset = range.startOffset;
                // 在光标位置处插入新的表情内容
                textNode.insertData(rangeStartOffset, emojiInput.value);
                // 添加了新内容,将光标移动到新的位置
                range.setStart(textNode, rangeStartOffset + emojiInput.value.length);
 
                // 将选区折叠为一个光标
                range.collapse(true);
                // 清除所有光标对象
                selection.removeAllRanges();
                // 添加新的光标对象
                selection.addRange(range);
            }
            // 记录最后光标对象
            lastEditRange = selection.getRangeAt(0)
        }
    </script>
</body>
 
</html>