在input、textarea光标处添加字符串(selection、range)

本文详细介绍了HTML5中关于文本选区和光标管理的相关知识,包括Selection对象、Range对象的使用,以及如何在input和contenteditable元素中操作选区和设置光标位置。通过示例代码展示了添加字符串、自定义选区、获取选中内容等功能,对于理解和应用文本操作具有指导意义。
摘要由CSDN通过智能技术生成

一、参考

  1. setSelectionRange()参考
  2. Selection MDN
  3. Range MDN

二、问题描述

业务需求:摄像头发现有违章停车,就需要短信通知到相关车主

开发任务:需要提前编辑好相关短信模板,比如时间、车牌号、车主名字等通用模板信息,需要使用特定字符代替,方便后台解析。而这些字符串是开发定的,对编写短信模板的人实际上没有实际意义

三、快速入门

<html>
  <head> </head>
  <script type="text/javascript">
    function add(str) {
      var tc = document.getElementById("mytextarea");
      var tclen = tc.value.length;
      tc.focus();
      // 兼容性检查
      if (typeof document.selection != "undefined") {
        document.selection.createRange().text = str;
      } else {
        tc.value =
          // 获取光标的开始位置
          tc.value.substr(0, tc.selectionStart) +
          str +
          tc.value.substring(tc.selectionStart, tclen);
      }
    }
  </script>
  <body>
    <textarea rows="5" name="s1" cols="27" id="mytextarea">
目的通过点击页面上的按钮button 在textarea中的光标停留处插上文字 </textarea
    >

    <ul>
      <li>
        <button onclick="add('huangbiao')">添加指定字符串</button>
      </li>
    </ul>
  </body>
</html>

四、HTML5中选中Selection和光标Range对象

光标是一个对象,当你选中某个元素的时候才会出现光标对象

  • 我们点击一个输入框,实际会产生一个选中对象-selection,这个对象我们可以通过indow.getSelection()来获取;
  • selection只存在1个,所以当你切换到其他输入框额时候,selection同样会跟着变化的。
  • 在选中的情况下有一个光标叫做range,和selection一样
  • 当你点击一个输入框,或者你切换到别的输入框,selection是会跟着变化的。光标就是在selection里面,光标叫做range,

4.1 选中对象-selection

  • Selection MDN

  • MDN 解释说明

    • Selection 对象表示用户选择的文本范围或插入符号的当前位置。它代表页面中的文本选区,可能横跨多个元素
    • 文本选区由用户拖拽鼠标经过文字而产生。要获取用于检查或修改的 Selection 对象,请调用 window.getSelection()
      • 一个 Selection 对象表示用户选择的 Range 的集合。通常,它只包含一个区域
	var selObj = window.getSelection();
	var range  = selObj.getRangeAt(0);
  • 个人理解

    • 当我们去点击一个输入框的时候,实际上它会产生一个选中对象-selection(就是我们可以看到的文字变成蓝色的那个区域),selection在火狐浏览器可以直接用 window.getSelection()获取,在HTML里面,selection只有一个的,并且selection是一个区域,你可以想象成一个长方形,它是有开始和结束的
  • selectionchange 事件

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div>
      Enter and select text here:<br /><input id="mytext" rows="2" cols="20" />
    </div>
    <div>selectionStart: <span id="start"></span></div>
    <div>selectionEnd: <span id="end"></span></div>
    <div>selectionDirection: <span id="direction"></span></div>
  </body>
  <script>
    const myinput = document.getElementById("mytext");
    // myinput.addEventListener("selectionchange", () => { 这个无效
    document.addEventListener("selectionchange", () => {
      // 只有HTMLInputElement 节点才有 selectionStart selectionEnd selectionDirection 属性
      document.getElementById("start").textContent = myinput.selectionStart;
      document.getElementById("end").textContent = myinput.selectionEnd;
      document.getElementById("direction").textContent =
        myinput.selectionDirection;
    });
  </script>
</html>

4.2 光标对象-range

  • Range MDN
  • MDN 概念
    • Range 接口表示一个包含节点与文本节点的一部分的文档片段
    • 范围指的是文档中连续的一部分。一个范围包括整个节点,也可以包含节点的一部分,例如文本节点的一部分。用户通常下只能选择一个范围,但是有的时候用户也有可能选择多个范围。
    • 可以用 Document 对象的 Document.createRange 方法创建 Range,也可以用 Selection 对象的 getRangeAt 方法获取 Range。另外,还可以通过 Document 对象的构造函数 Range() 来得到 Range。
  • 个人理解
    • 光标就是在selection里面,光标叫做range,是一个片段区域,和selection一样,有开始点,和结束点,当我们对文字按下左键向右拉的时候,就看到了文字变成蓝色,那个就是光标的开始和结束
    • 当我们直接点一下的时候,光标在闪,其实只是开始和结束点重叠了

4.3 HTMLInputElement.setSelectionRange()

  • setSelectionRange()参考
  • 函数作用
    • 于设定 或 元素中当前选中文本的起始和结束位置。
    • 个人理解:设置光标的位置
  • 属性
    • selectionStart
      被选中的第一个字符的位置索引,从0开始。如果这个值比元素的 value 长度还大,则会被看作 value 最后一个位置的索引。
    • selectionEnd
      被选中的最后一个字符的 下一个 位置索引。如果这个值比元素的value长度还大,则会被看作value最后一个位置的索引。
    • selectionDirection 可选
      一个表示选择方向的字符串,可能的值有: “forward” 、 “backward”、 “none” 默认值,表示方向未知或不相关。

五、代码集合

5.1选中input表单的内容,展示位置

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div>
      Enter and select text here:<br /><input id="mytext" rows="2" cols="20" />
    </div>
    <div>selectionStart: <span id="start"></span></div>
    <div>selectionEnd: <span id="end"></span></div>
    <div>selectionDirection: <span id="direction"></span></div>
  </body>
  <script>
    const myinput = document.getElementById("mytext");
    // myinput.addEventListener("selectionchange", () => { 这个无效
    document.addEventListener("selectionchange", () => {
      // 只有HTMLInputElement 节点才有 selectionStart selectionEnd selectionDirection 属性
      document.getElementById("start").textContent = myinput.selectionStart;
      document.getElementById("end").textContent = myinput.selectionEnd;
      document.getElementById("direction").textContent =
        myinput.selectionDirection;
    });
  </script>
</html>

5.2 在文本控件的光标位置添加 字符串

<html>
  <head> </head>
  <script type="text/javascript">
    function add(str) {
      var tc = document.getElementById("mytextarea");
      var tclen = tc.value.length;
      tc.focus();
      if (typeof document.selection != "undefined") {
        document.selection.createRange().text = str;
      } else {
        tc.value =
          // 获取光标的开始位置
          tc.value.substr(0, tc.selectionStart) +
          str +
          tc.value.substring(tc.selectionStart, tclen);
      }
    }

    // 文本表单内容全部选中
    function selectAll() {
      var tc = document.getElementById("mytextarea");
      // textarea 内容全部选中
      tc.select();
      // 聚焦选中
      tc.focus();
    }

    function selectPos() {
      var start = 5,
        end = 10;
      var tc = document.getElementById("mytextarea");
      // 没有选中,默认全部是从 0 开始
      console.log(tc.selectionStart);
      // 没有选中区域,则和 selectionStart 在相同的位置
      console.log(tc.selectionEnd);
      // 设置选中的区域,不会在浏览器中高亮选中的内容
      tc.setSelectionRange(start, end);
      // 选中的开始位置
      console.log(tc.selectionStart);
      // 选中的结束位置
      console.log(tc.selectionEnd);
      var str = "huangbiao";
      var tclen = tc.value.length;
      tc.value =
        tc.value.substr(0, tc.selectionStart) +
        str +
        tc.value.substring(tc.selectionStart, tclen);
    }

    function getSelectObj() {
      // 获取用户页面选中的对象
      var selObj = window.getSelection();
      // 调用 Selection.toString() 方法会返回被选中区域中的纯文本。
      window.alert(selObj);
    }

    function getRangeObj() {
      var selObj = window.getSelection();
      // 获取Range 对象
      var range = selObj.getRangeAt(0);
      console.log(range);
    }
  </script>
  <body>
    <textarea rows="5" name="s1" cols="27" id="mytextarea">
目的通过点击页面上的按钮button 在textarea中的光标停留处插上文字 </textarea
    >

    <ul>
      <li>
        <button onclick="selectAll()">
          全部选中
        </button>
      </li>
      <li>
        <button onclick="add('huangbiao')">添加指定字符串</button>
      </li>
      <li>
        <button onclick="selectPos()">
          自定义选中的位置
        </button>
      </li>
      <li>
        <button onclick="getSelectObj()">
          获取选中的值
        </button>
      </li>
      <li>
        <button onclick="getRangeObj()">
          获取选中的Range对象
        </button>
      </li>
    </ul>
  </body>
</html>

5.3 自定义光标位置 或者 删除选中内容

<html>
  <head> </head>
  <script type="text/javascript">
    // 要把元素清空
    function clearContent() {
      var p = document.getElementById("mytextarea"),
        s = window.getSelection(),
        r = document.createRange();
        debugger
      // 兼容 contenteditable="true" 属性 和 input 表单两种情况
      p.innerHTML = "\u00a0";
      // 光标选中节点
      r.selectNodeContents(p);
      // 选中对象 删除所有的光标
      s.removeAllRanges();
      // 选中对象 插入自定义的光标对象
      s.addRange(r);
      // 将光标选中的对象删除
      // document.execCommand("delete", false, null);
    }

    // 将光标放在第一个位置
    function addFirst() {
      var p = document.getElementById("mytextarea"),
        s = window.getSelection(),
        r = document.createRange();
      // 设置光标在 p 控件的开始位置
      r.setStart(p, 0);
      // 设置光标在 p 控件的结束位置
      r.setEnd(p, 0);
      // 选中对象 删除所有的光标
      s.removeAllRanges();
      // 选中对象 插入自定义的光标对象
      s.addRange(r);
      // 聚焦到可编辑的文本控件中
      p.focus();
    }
  </script>
  <body>
    <div contenteditable="true" id="mytextarea">
      我是一句优美的语言
    </div>
    <ul>
      <li>
        <button onclick="addFirst()">将光标放在第一个位置</button>
      </li>
      <li>
        <button onclick="clearContent()">要把元素清空</button>
      </li>
    </ul>
  </body>
</html>

5.4在contenteditable属性标签中光标位置添加文本

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></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)
                
                if (edit.childNodes.length > 0) {
                    // 如果文本框的子元素大于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>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值