文本标记 - 用户从网页上选择文本高亮

在上一篇文章 文本标记 - 高亮标记多个指定位置的文本 中, 说明了如何高亮后台返回的指定位置的多个数据. 现在解释下一个需求: 用户在高亮后台返回的数据的基础上, 从页面上选择文本高亮, 并且在表格中显示文本

上篇文章说到高亮的效果: 一般都是给指定的文本包裹一个标签 ( 如 ), 在给这个标签设置一个样式 ( 比如添加背景色 ), 这是实现这个需求的基础.

ps: 如果只有用户从网页上选择文本的需求, 可以考虑用 web-highlighter 插件, 比起自己手写方法来要简便一些.

首先介绍一下这个需求的逻辑:

  1. 点这个知识抽取的按钮, 然后左边文本高亮, 右面的表格填充 (实体这一列为只读状态), (有多个表格, 采取了不同的高亮样式)
    在这里插入图片描述

  2. 点击这个按钮, 对应的高亮消失, 表格变空
    在这里插入图片描述

  3. 用户从左边文本选择一段, 像这样; 再点击这个对钩, 就会填充, 然后获取它对应的下标起始位置, 保存下来, 并且将选中的文本高亮
    在这里插入图片描述

这里的难点就是, 因为已经标记了后台返回的那些文本, 然后这些高亮文本都被包裹了span标签. 这时候获取的下标就不是从整个文本对应的下标0开始的了, 因为整个文本被span标签分成了很多部分, 用户标记的时候, 获取的这个下标只是这个分段里的下标, 但是我们要传给后端相对于整篇文本的下标, 这就是难点.

通过对不同位置的selection对象的研究 , 发现了以下几个不同点:

  1. 普通文本的
    a) parentNode是 <div class="fileText">...</div>
    b) previousSibling是前一个已经标记的元素节点, 元素节点的nodeType=1, className可以看到该元素节点的类名; nextSibling也是已标记的元素节点

  2. 已标记文本的
    a) parentNode是当前标签, eg. <span class="EntityHighlight">纯电动汽车</span>
    b) previousSibling 和 nextSibling都是null

  3. 判断是否是开头的普通文本:
    a) parentNode是整个div

后台返回的某个高亮本文对象:
在这里插入图片描述

思路

  1. 首先通过baseNode的parentNode是div还是span判断是普通文本还是标记文本,
  2. 如果是普通文本, 通过previousSibling寻找前面的元素节点:
    a) 如果返回null => 说明是开头的元素, 直接用
    开始位置: baseOffset
    结束位置: baseOffset+length-1
    b) 如果返回某个元素节点 => 通过className判断是table1还是table2里的元素 (项目中不只有右边一个表格, 这几个表格中使用了不同的高亮样式), 然后 前兄弟节点的end+1+baseOffset 就是用户选择的selection相对于整个文本的开始位置, 结束位置可以是: 开始位置+选中文本.length-1
  3. 如果是标记文本, 根据它的className判断是table1还是table2中的元素, 获取对应的start.
    开始位置: start+baseOffset
    结束位置: 开始位置+选中文本.length-1

代码

// 知识抽取按钮
    knowExtract() {
      if (this.isEdit) {
        this.$alert("请先保存文本");
      } else {
        const _key = this.extract_key;
        console.log(_key);
        knowiExtract(_key).then((res) => {
          console.log(res);
          if (res.status == 0) {
            // 知识抽取成功
            this.$message.success(res.message);

            // 表1数据渲染
            this.tableData1 = res.entity;
            console.log(this.tableData1);

            // 表2数据渲染
            // this.tableData2 = res.attribute

            // 表1文本高亮
            this.highlightEntity();
          } else {
            this.$message.error("知识抽取失败");
          }
        });
      }
    },

    // 表1 文本高亮
    highlightEntity() {
      console.log("文本高亮");
      let text = this.fixedText
      let textList = text.split("");

      // 表1中的实体高亮
      this.tableData1.forEach((item) => {
        let startNum = item.start;
        let endNum = item.end + 1;
        console.log(startNum,endNum)

        if (startNum == endNum - 1) {
          textList[startNum] = `<span class="EntityHighlight">${textList[startNum]}</span>`;
        } else {
          textList[startNum] = `<span class="EntityHighlight">${textList[startNum]}`;
          textList[endNum - 1] = `${textList[endNum - 1]}</span>`;
        }
      });

      // 表2 中的文本高亮

      this.text = textList.join("");
    },

    // 表1 实体高亮初始化 (编辑按钮)
    initEntiExtract(i) {
      this.$message.warning("请从前向后选择文本内容")
      console.log("实体高亮初始化" + i);
      this.tableData1[i].entity = ""
      this.tableData1[i].start = ""
      this.tableData1[i].end = ""
      console.log(this.tableData1)
      this.highlightEntity()

      this.selection = window.getSelection();
    },

    // 表1 实体抽取  (√按钮)
    entityExtract(i) {
      console.log(this.selection);
      let newEntiry = this.selection.toString();

      // 保证起始位置小于结束位置 (用户倒选的操作)(未完成)
      

      // 获取截取开头的baseNode
      let startNode = this.selection.baseNode
      // 根据parentNode是div还是span判断是普通文本还是标记文本
      let startParent = startNode.parentNode.nodeName
      console.log("parentNode 父节点")
      console.log(startParent)

      if (startParent == "DIV") {
        // 普通文本, 通过previousSibling寻找前面的元素节点
        let preSib = startNode.previousSibling
        console.log("前兄弟节点")
        console.log(preSib)
        if (!preSib) {
          console.log("前兄弟节点不存在")
          // 如果返回null => 说明是开头的元素, 直接用开始位置: baseOffset,结束位置: baseOffset+length-1
          this.tableData1[i].start = this.selection.baseOffset
          this.tableData1[i].end = this.selection.baseOffset + newEntiry.length - 1
          console.log("起始位置")
          console.log(this.tableData1[i].start, this.tableData1[i].end)
        } else {
          let preSibClass = preSib.className
          console.log("前兄弟节点的className")
          console.log(preSibClass)
          if (preSibClass == "EntityHighlight") {
            // 表1元素
            // 寻找前兄弟节点的end位置
            let preSibEnd = 0
            for(let k=0;k<this.tableData1.length;k++){
              if(this.tableData1[k].entity == preSib.innerText){
                console.log(preSib.innerText)
                console.log(this.tableData1[k].end)
                preSibEnd = this.tableData1[k].end
              }
            }
            console.log("前兄弟节点的end位置")
            console.log(preSibEnd)

            this.tableData1[i].start = preSibEnd + 1 + this.selection.baseOffset
            this.tableData1[i].end = this.tableData1[i].start + newEntiry.length - 1
            console.log("起始位置")
            console.log(this.tableData1[i].start, this.tableData1[i].end)
          }
        }

      } else if (startParent == "SPAN") {
        // 标记文本, 根据它的className判断是table1还是table2中的元素
        let nodeClass = startNode.className
        console.log(nodeClass)
        if (nodeClass == "EntityHighlight"){
          // 表1元素
          // 获取起始位置
          for(let j=0;j<this.tableData1.length;j++) {
            if( this.tableData1[j].entity = startNode.nodeValue) {
              this.tableData1[i].start = this.tableData1[j].start + this.selection.baseOffset
              this.tableData1[i].end = this.tableData1[i].start + this.selection.length - 1
            }
          }
        }
      }
      
      // 给table1中相应的entity赋值
      this.tableData1[i].entity = newEntiry;

      console.log(this.tableData1)
      this.highlightEntity()
    },
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
HTML(HyperText Markup Language)是用于创建网页的标准标记语言,其文本标记主要用于定义文本的样式、结构和交互。以下是几个基本的文本标记: 1. **普通文本**: 使用`<p>`标签表示段落,例如 `<p>这是段落文本。</p>`。 2. **斜体和粗体**: 使用`<i>`标签表示斜体,如 `<i>这是一些斜体文本</i>`;使用`<b>`或`<strong>`标签表示粗体,如 `<b>这是一些粗体文本</b>`。 3. **删除线**: 在HTML5中没有直接的删除线标记,但可以通过CSS实现,如`:before`伪元素配合`content: "~~"`, 如 `(<span style="position:relative; display:inline-block; overflow:hidden;">已删除的文字<span style="position:absolute; top:-1px; left:0; padding:0 4px; font-size:90%; white-space:nowrap;">~~</span></span>)`。 4. **高亮**: 使用`<mark>`标签可以高亮显示文本,例如 `<mark>这是被高亮文本</mark>`。 5. **文本划线**: HTML本身没有直接支持文本划线的标记,但可以通过CSS `text-decoration: underline`来实现,如 `<span style="text-decoration: underline;">划线文本</span>`。 6. **框选**(鼠标选择区域): 浏览器默认行为,用户可以直接在页面上选择文本。若需自定义选择区域,通常需要JavaScript配合。 对于文本框和下拉框,可以使用`<input type="text">`和`<select>`标签,分别创建输入框和下拉列表,比如: ```html <input type="text" placeholder="输入文本..."> <select> <option value="option1">选项1</option> <option value="option2">选项2</option> </select> ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Charonmomo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值