资讯专栏INFORMATION COLUMN

JavaScript之Range--或许会有点用

stonezhu / 1090人阅读

摘要:不过在细说之前我们先了解一下。这时候就是发挥作用的地方了。可以将一个对象转化为对象。这四个属性可以定位一段被选中的文字。如上图,我们知道元素排列是一段一段的,这里的就是指的每个段,就是选中的位置。肯定是连续的,这样我们就可以定位一段完整的。

Range是JavaScript的内置对象,一般来讲用到的地方不是很多,主要是一些交互性比较强的场景可能会用到,比如高亮标注,用不到还好说,如果用到了查资料确实也是比较少的, 所以这里总结一下笔记,不会太深入。

需要注意的是这里很多方法都属于实验性功能, 所以生产环境使用的使用需要谨慎,具体可以参考MDN。这里不赘述了。

range的应用场景

这类相对比较生僻的api应用常见并不是很多, 这里我们先了解一下range的应用场景.

就是常见的高亮标注电子书之类的

人工标注机器学习所需的基础文档(我所做的)

当然应该也有很多其他场景, 我也没怎么接触. 有兴趣的可以自行了解

Range是什么

顾名思义,Range其实可以认为是一个选中的文字范围, 但是Range又不依赖于鼠标选中, 我们可以自行构造或者克隆。不过在细说Range之前我们先了解一下Selection。

如图当我们选中一段文字时, 我们就以通过window.getSelection来获取Selection对象

Selection可以window.getSelection().toString()直接获取选中的文字, 但是很多时候我们并不是要获取选中的文字,而是要得到选中文字所在位置并将其存储起来。这时候就是Range发挥作用的地方了。

window.getSelection().getRangeAt(0)可以将一个Selection对象转化为Range对象。

我们需要关注的东西是startContainer,endContainer, startOffset,endOffset。这四个属性可以定位一段被选中的文字。

如上图,我们知道Dom元素排列是一段一段的, 这里的container就是指的每个段,offset就是选中的位置。Range肯定是连续的,这样我们就可以定位一段完整的Range。

Range的存储

如果作为高亮, Range必然是要存到服务器上的, 但是作为js对象, Range不可以直接存到数据库里,这时候就要对Range进行一定的处理了。

上面提到过Range是可以手动创建的:document.createRange

var range = document.createRange();

range.setStart(startNode, startOffset);
range.setEnd(endNode, endOffset);

这里startNode指startContainer, 自然就是指dom元素了,看到这里其实大家心里也该有点方案了,不好存储的无非就是dom元素了,那我们将dom元素转为选择器存起来就好了, 到时再通过选择器获取dom元素。

当然我们也有其他选择: xpath, 主要是我接手项目的时候就是利用的xpath, 将dom转为xpath的代码如下:

// 获取一个元素的xpath
function getElementXPath (element) {
  if (!element) return null

  if (element.id) {
    return `//*[@id=${element.id}]`
  } else if (element.tagName === "BODY") {
    return "/html/body"
  } else {
    const sameTagSiblings = Array.from(element.parentNode.childNodes)
      .filter(e => e.nodeName === element.nodeName)
    const idx = sameTagSiblings.indexOf(element)

    return getElementXPath(element.parentNode) +
      "/" +
      element.tagName.toLowerCase() +
      (sameTagSiblings.length > 1 ? `[${idx + 1}]` : "")
  }
}

将xpath转化为Range:

function createRangeFromXPathRange (xpathRange) {
    var startContainer,
      endContainer,
      endOffset,
      evaluator = new XPathEvaluator()

    // must have legal start and end container nodes
    startContainer = evaluator.evaluate(
      xpathRange.startContainerPath,
      document.documentElement,
      null,
      XPathResult.FIRST_ORDERED_NODE_TYPE,
      null
    )
    if (!startContainer.singleNodeValue) {
      return null
    }

    if (xpathRange.collapsed || !xpathRange.endContainerPath) {
      endContainer = startContainer
      endOffset = xpathRange.startOffset
    } else {
      endContainer = evaluator.evaluate(
        xpathRange.endContainerPath,
        document.documentElement,
        null,
        XPathResult.FIRST_ORDERED_NODE_TYPE,
        null
      )
      if (!endContainer.singleNodeValue) {
        return null
      }

      endOffset = xpathRange.endOffset
    }

    // map to range object
    var range = document.createRange()
    range.setStart(startContainer.singleNodeValue, xpathRange.startOffset)
    range.setEnd(endContainer.singleNodeValue, endOffset)
    return range
  }
总结

这篇文章笔记不会介绍太多api或者太过深入, 但是用法思路是一定的。共勉。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/107907.html

相关文章

  • 理解 JavaScript(四)

    摘要:其工作原理我已经在第一篇做了大部分的阐述我尚未提及的是在创建新对象的时候,会赋予新对象一个属性指向构造器的属性。 第四篇拖了很久了,真是有点不好意思。实话实说,拖延很久的原因主要是没想好怎么写,因为这一篇的主题比较有挑战性:原型和基于原型的继承——啊~我终于说出口了,这下没借口拖延了== 原型 我(个人)不喜欢的,就是讲原型时上来就拿类做比较的,所以我不会这样讲。不过我的确讲过构造器函...

    cuieney 评论0 收藏0
  • 前端性能优化 JavaScript

    摘要:大多数情况下,对一个直接量和一个局部变量数据访问的性能差异是微不足道的。 前端性能优化之 JavaScript 前言 本文为 《高性能 JavaScript》 读书笔记,是利用中午休息时间、下班时间以及周末整理出来的,此书虽有点老旧,但谈论的性能优化话题是每位同学必须理解和掌握的,业务响应速度直接影响用户体验。 一、加载和运行 大多数浏览器使用单进程处理 UI 更新和 JavaScri...

    Coding01 评论0 收藏0
  • JavaScriptWeb Worker

    摘要:使用要点同源限制分配给线程运行的脚本文件,必须与主线程的脚本文件同源。限制线程所在的全局对象,与主线程不一样,无法读取主线程所在网页的对象,也无法使用这些对象。通信联系线程和主线程不在同一个上下文环境,它们不能直接通信,必须通过消息完成。 介绍 Web Worker为Web内容在后台线程中运行脚本提供了一种简单的方法。线程可以执行任务而不干扰用户界面。此外,他们可以使用XMLHttpR...

    BigNerdCoding 评论0 收藏0
  • 单文件组件下的vue,可以擦出怎样的火花

    摘要:线上另加入了排行榜功能,如需查看源码的,请切换到分支整个项目结构清晰,尤其单文件组件的表现力尤为突出,使得每个组件的逻辑都没有过于复杂,而且在的统筹下,的单向数据流模式使得所有的变化都在可控制可预期的范围内。 2016注定不是个平凡年,无论是中秋节问世的angular2,还是全面走向稳定的React,都免不了面对另一个竞争对手vue2。喜欢vue在设计思路上的先进性(原谅我用了这么一个...

    Keven 评论0 收藏0
  • 趣味Python题目10月8日

    摘要:最近在自学,无意看到群友一道比较有趣的问题,故尝试给出答案。目前给出的版本是最简单的情况,没有考虑比较牌大小中出现数字或者字母重复的情况,以后有时间或许会给出更精细的版本。编写程序,进行扑克牌大小比较。 最近在自学Python,无意看到群友一道比较有趣的问题,故尝试给出答案。目前给出的版本是...

    Mertens 评论0 收藏0

发表评论

0条评论

stonezhu

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<