DOM TreeWalker 返回所有文本节点

2024-06-19

我试图访问给定元素内的所有文本节点,以便我可以隔离单词并将它们包装在跨度中。

TreeWalker似乎是这项工作的 API,但我发现它非常不直观。既没有spec http://www.w3.org/TR/DOM-Level-2-Traversal-Range/traversal.html也不MDN 参考 https://developer.mozilla.org/en-US/docs/Web/API/Document/createTreeWalker(通常非常擅长解释神秘的 DOM API)在我看来是不言而喻的。

我的第一个假设是我需要传递的只是正确的过滤器作为第二个参数 - 类似于document.createTreeWalker( element, NodeFilter.TEXT_NODE )。但这似乎一遇到非文本节点就停止了:

wordWrap( document.body )

function wordWrap( element ){
  var nodes = document.createTreeWalker( element, NodeFilter.TEXT_NODE )
  var node
  var text
  var word

  while( node = nodes.nextNode() ){
    text = node.nodeValue.replace( /(^\s+|\s+$)/, '' ).split( /\s+/g )

    while( text.length ){
      word = document.createElement( 'span' )

      word.className = 'word'

      word.innerText = text.shift()

      node.parentNode.insertBefore( word, node )

      if( text.length )
        node.parentNode.insertBefore( document.createTextNode( ' ' ), node )
        }

    node.parentNode.removeChild( node )
  }
}
.word {
  background: #fee;
  padding: 0 .5em 0 0;
}
Contact us at <a href="mailto:[email protected] /cdn-cgi/l/email-protection">[email protected] /cdn-cgi/l/email-protection</a> for submissions &#38; other enquiries.

所以我认为这是使用第三个过滤器参数的机会TreeWalker,以及额外的属性NodeFilter。如果过滤器方法的有效返回值是FILTER_ACCEPT, FILTER_REJECT & FILTER_SKIP,然后我推断,通过在第二个参数中接受元素节点和文本节点,我可以指定应该接受文本节点并跳过其余节点。但这似乎给出了相同的结果 - 在锚点之内或之后没有拾取任何文本节点:

wordWrap( document.body )

function wordWrap( element ){
  var nodes = document.createTreeWalker(
    element,
    NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT,
    { acceptNode : function( node ){
      if( node.nodeType === node.TEXT_NODE )
        return NodeFilter.FILTER_ACCEPT
      else 
        return NodeFilter.FILTER_SKIP
    } } 
  )
  var node
  var text
  var word

  while( node = nodes.nextNode() ){
    text = node.nodeValue.replace( /(^\s+|\s+$)/, '' ).split( /\s+/g )

    while( text.length ){
      word = document.createElement( 'span' )

      word.className = 'word'

      word.innerText = text.shift()

      node.parentNode.insertBefore( word, node )

      if( text.length )
        node.parentNode.insertBefore( document.createTextNode( ' ' ), node )
        }

    node.parentNode.removeChild( node )
  }
}
.word {
  background: #fee;
  padding: 0 .5em 0 0;
}
Contact us at <a href="mailto:[email protected] /cdn-cgi/l/email-protection">[email protected] /cdn-cgi/l/email-protection</a> for submissions &#38; other enquiries.

至此,我确信使用 DOM1 方法递归地迭代树会更容易,如以下代码片段所示:

wordWrap( document.body )

function wordWrap( element ){
  textNodes( element ).forEach( function( node ){
    var text = node.nodeValue.split( /\s+/g )
    var word

    while( text.length ){
      word = document.createElement( 'span' )

      word.className = 'word'

      word.innerText = text.shift()

      node.parentNode.insertBefore( word, node )

      if( text.length )
        node.parentNode.insertBefore( document.createTextNode( ' ' ), node )
        }

    node.parentNode.removeChild( node )
  } )
}

function textNodes( element ){
  var nodes = []

  Array.prototype.forEach.call( element.childNodes, function( child ){
    if( child.nodeType === child.TEXT_NODE )
      nodes = nodes.concat( child )
      else if( child.nodeType === child.ELEMENT_NODE )
        nodes = nodes.concat( textNodes( child ) )
        } )

  return nodes
}
.word {
  background: #fee;
  padding: 0 .5em 0 0;
}
Contact us at <a href="mailto:[email protected] /cdn-cgi/l/email-protection">[email protected] /cdn-cgi/l/email-protection</a> for submissions &#38; other enquiries.

我缺少什么?


我缺少什么?

node.parentNode.removeChild(node)问题是 - 你正在从 DOM 中删除当前节点,所以 walker 会发现没有.nextNode()从那里。

您应该在删除节点之前推进步行器,或者只是不删除它而是缩小其内容(到移出所有单词后剩下的内容)。

wordWrap(document.body);

function wordWrap( element ){
  var nodes = document.createTreeWalker(element, NodeFilter.SHOW_TEXT, null, null);
  var node;
  while (node = nodes.nextNode()) {
    var p = node.parentNode;
    var text = node.nodeValue;
    var m;
    while(m = text.match(/^(\s*)(\S+)/)) {
      text = text.slice(m[0].length);
      p.insertBefore(document.createTextNode(m[1]), node);
      var word = p.insertBefore(document.createElement('span'), node);
      word.appendChild(document.createTextNode(m[2]));
      word.className = 'word';
    }
    node.nodeValue = text;
  }
}
.word {
  background: #faa;
  padding: 0 .5em 0 0;
}
Contact us at <a href="mailto:[email protected] /cdn-cgi/l/email-protection">email @ example.com</a> for submissions &#38; other enquiries.

Notice that the correct filter is NodeFilter.SHOW_TEXT, not .TEXT_NODE, and that in older browser the four arguments are not optional.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

DOM TreeWalker 返回所有文本节点 的相关文章

随机推荐

  • 如何将 Datagridview 中的格式列更改为该值的日期类型

    例如 我有这样的值 41607 2069444444 41607 2068402778 41607 2072222222 这是来自 CDR 的 dateTimeOrigination 计算 在 Excel 中 我将格式单元格更改为日期类型
  • 将所有文件与指定目录(和子目录)中的所有文件进行二进制比较

    我需要将目录及其子目录中包含的所有文件与同一目录及其子目录中包含的所有其他文件进行比较 并将匹配文件的路径记录到文本文件或 CSV 我意识到有一些软件工具可以做到这一点 但除非它可以在 Windows 中开箱即用 否则我将不被允许在我的网络
  • Visual Studio 2019 F# NU1101 无法找到包 FSharp.core

    我刚刚开始使用 Microsoft Visual Studio 和 F 我已尽可能地遵循他们的教程 但是当我尝试运行代码时 他们告诉我收到错误 NU1101 Unable to find package FSharp Core No pac
  • PHP MYSQL文件内容转义问题

    我正在尝试使用 php 将 pdf 文件上传到 mysql 数据库中 除了文件内容之外 一切都很好 无论我如何尝试转义特殊字符 查询总是失败 主要是 未知命令 n 我使用过addslashes mysql real escape strin
  • 如何使用 PetaPoco 库自动从数据库创建模型?

    我的数据库中有一个表 我想为其创建一个带有 getter 和 setter 的模型类 对于我项目中的大部分任务 我使用 PetaPoco 我手动创建了模型 但很少有表有很多列 有没有办法使用 PetaPoco 从数据库创建模型 我强烈建议您
  • 为什么包含此模块不会覆盖动态生成的方法?

    我试图通过包含一个模块来覆盖动态生成的方法 在下面的示例中 Ripple 关联添加了rows 方法表 我想调用该方法 但之后还要做一些额外的事情 我创建了一个模块来重写该方法 认为该模块的row 可以打电话super使用现有的方法 clas
  • iOS 中的内存泄漏,AVPlayer 永远不会被释放

    我使用了 AVPlayerDemo 示例苹果文档 https developer apple com library ios samplecode AVPlayerDemo Introduction Intro html并在其上编写了我自己
  • 在 Mono 上运行 .Net MVC5 应用程序

    我正在 Windows 上的 Visual Studio 2013 中开发 Net 4 5 1 MVC5 应用程序 现在我想知道 是否可以在Linux Ubuntu 12 04 上运行这个应用程序 可以使用OWIN吗 Owin 可以自托管运
  • 通过 Java 连接 Apache Drill

    在 Apache Drill 的 Wiki 中 我只能看到通过 SqlLine 客户端运行的查询 除了 REST API 之外 是否有任何编程方式可以在 Drill 中运行查询 有任何示例或指示吗 或者它与使用 JDBC 驱动程序运行 SQ
  • 如果遵循 REST 架构,如何访问 codeigniter 中的 URL 参数?

    以下是可用于访问资源的基于 REST 的有效 URL 使用codeigniter 如何访问下面传递的参数1 我在教程中看到了上述内容并设置了我的代码 然而显然 id this gt input gt get id 不起作用 Using th
  • 没有这样的命名空间:clojurescript 项目设置中的 clojure.spec.alpha

    我在尝试学习clojure spec 在沿着启动构建工具设置 clojure 项目时 我在需要 clojure spec alpha 时遇到以下错误 Compiling ClojureScript js app js No such nam
  • 在java中执行外部程序并传递命令

    我有这个国际象棋引擎 Rybka exe 我必须在 java 中执行 以下是如何运行 Rybka 的示例 单击它后 控制台将打开并等待输入 然后你输入 uci 并按 Enter 键并等待它加载 大约 1 秒 然后你必须输入更多行作为选项和内
  • 检测 Java JAR/代码篡改

    我正在编写一个以 JAR 文件形式分发的软件 目前 该 JAR 文件可以被篡改以检索并保存我们的服务器通过以下方式传输的另一个文件URLClassLoader 进行反编译 并在我们的代码中找到应保持私有的各种内容 以确保使用它的客户端的安全
  • Django 检索 GET 列表

    我是 Django 新手 我有一个 URL 列表 例如 example com item test item for test url 我知道如何在视图中检索该值 a request GET getlist item 我的问题是 如何在模板
  • 使用 Flutter 3.10 / Dart 3.0 进行 VS Code 调试<优化>

    在最新的 颤振 升级 之后 我在 VS Code 调试期间查看某些变量时遇到问题 如何在悬停时查看变量的内容而不是获取此内容 Screenshot of hovering variable 这仅发生在某些变量上 其他变量我可以正常查看内容
  • tkinter:无法使框架可滚动

    在 python tkinter 上 我在顶级窗口上使用 2 个不同的框架 一个在右侧 另一个在左侧 右侧的框架不可滚动 我在该框架的框架顶部创建了一个画布 并在该画布顶部创建了另一个框架 我已使该画布可滚动并将小部件粘贴到该画布上 但它不
  • 在iPhone上将CSV文件读入sqlite3

    有没有办法在iPhone上将CSV文件读入sqlite3 sqlite3 是否有类似于 SQL 命令的功能 LOAD DATA LOCAL INFILE file csv INTO TABLE TABLENAME FIELDS TERMIN
  • 将列表数据放入地图时出现异常

    我正在迭代一个列表并将其内容放在地图上 但问题是 当我返回该地图时 我遇到了异常 您能否告知其背后的原因是什么 我收到了 java lang IndexOutOfBoundsException 索引 100 大小 100 因为我的列表大小是
  • 在 swift 3 的 textview 中显示属性文本?

    我想以斜体 粗体显示从服务器收到的文本 你好世界所以 responseObj text p b i hello i b i world gt i p if let postText String responseObj text as St
  • DOM TreeWalker 返回所有文本节点

    我试图访问给定元素内的所有文本节点 以便我可以隔离单词并将它们包装在跨度中 TreeWalker似乎是这项工作的 API 但我发现它非常不直观 既没有spec http www w3 org TR DOM Level 2 Traversal