【问题标题】:Replacing text in TextNode with new DOM node based on regular expression基于正则表达式用新的DOM节点替换TextNode中的文本
【发布时间】:2015-09-26 12:44:59
【问题描述】:

我有一个预处理 HTML DOM 中的文本节点的函数。

目的本质上是执行一些插值或字符串模板。

该函数主要检查匹配正则表达式 /\${([^}]*)}/g/{{([^}]*)}/g 的事件。

示例:${foo + 1}{{foo + 2}}

一切正常。

但我的目标是用新节点(例如 span)替换这些事件,这些节点由包含正则表达式匹配的内部值的 Knockout 绑定表达式组成。位置正确。保留出现的空格。

像这样:

<span ko-text="foo" /> for ${foo}(注意:自定义绑定语法)

我无法用TextNode.splitText 来解决这个问题。

我如何实现这一目标?

这是我目前得到的代码:

preprocessNode(node: Element) {
    if ("nodeValue" in node && node.nodeValue !== null) {
        var value = node.nodeValue;
        var match = value.matchAll(/\${([^}]*)}/g);
        if (!match) {
            match = value.matchAll(/{{([^}]*)}/g);
        }
        if (match !== null && match.length > 0) {
            var parentNode = node.parentNode;
            for (let entry of match) {
                var offset = node.nodeValue.indexOf(entry[0]);
                var oldNode = node;
                node = node.splitText(offset);

                var newNode = document.createElement("span");
                newNode.setAttribute("ko-text", entry[1]);
                node.parentNode.appendChild(newNode);
            }
            return [parentNode, parentNode];
        }
    }
    return null;
}

函数matchAll是自定义函数。

【问题讨论】:

  • 我认为您最好删除当前文本节点,然后在该位置插入新节点流。您可以使用单个正则表达式,使用全局搜索循环。由于您最终会混合新的文本节点和跨度元素,因此您必须考虑正则表达式中的文本之间的中间值。

标签: javascript html regex dom knockout.js


【解决方案1】:
var textNodesWalker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null, false);
var node;
while (node = textNodesWalker.nextNode()) {
    var newNodes = [];
    var execResult = MY_REG_EXP.exec(node.nodeValue);
    var start = 0;
    while (execResult) {
        newNodes.push(document.createTextNode(node.nodeValue.substring(start, execResult.index)));
        var generatedElement = ...; // create element (document.createElement) based on execResult
        newNodes.push(generatedElement);
        start = execResult.index + execResult[0].length;
        execResult = MY_REG_EXP.exec(node.nodeValue);
    }
    if (newNodes.length == 0) {
        continue;
    }
    newNodes.push(document.createTextNode(node.nodeValue.substring(start, node.nodeValue.length)));
    for (var i=0; i<newNodes.length; i++) {
        node.parentNode.insertBefore(newNodes[i], node)
    }
    node.parentNode.removeChild(node);
}

假设我们的模式/asdf/g 需要加粗。我的代码将转换为以下 html:

<p>Begin asdf End</p>

<p>Begin <b>asdf</b> End</p>

【讨论】:

    【解决方案2】:

    经过多方考虑,我是这样解决的:

    if (match !== null && match.length > 0) {
      var parentNode = node.parentNode;
      var nodes = [];
      var textString = value;
      var i = 0;
      for (let entry of match) {
        var startOffset = node.nodeValue.indexOf(entry[0]);
        var endOffset = startOffset + entry[0].length;
    
        var length = startOffset - i;
        if (length > 0) {
          var str = textString.substr(i, length);
          var textNode = document.createTextNode(str);
          parentNode.insertBefore(textNode, node);
        }
    
        var newNode2 = document.createElement("span");
        newNode2.setAttribute("ko-text", entry[1]);
        parentNode.insertBefore(newNode2, node);
    
        nodes.push(newNode2);
    
        i = endOffset;
      }
    
      var length = textString.length - i;
      if (length > 0) {
        var str = textString.substr(i, length);
        var textNode = document.createTextNode(str);
        parentNode.insertBefore(textNode, node);
      }
      parentNode.removeChild(node);
      return nodes;
    }
    

    当然可以改进。

    【讨论】:

      【解决方案3】:

      免责声明:我不懂 JavaScript!这只是一个建议。

       #  /^\$\{([^{}]+)\}|\{\{([^{}]+)\}\}|((?:(?!^\$\{[^{}]+\}|\{\{[^{}]+\}\})[\S\s])+)/
      
         ^ \$\{
         ( [^{}]+ )                    # (1)
         \}
      |  
         \{\{ 
         ( [^{}]+ )                    # (2)
         \}\}
      |  
         (                             # (3 start)
              (?:
                   (?!
                        ^ \$\{ [^{}]+ \}
                     |  \{\{ [^{}]+ \}\}
                   )
                   [\S\s] 
              )+
         )                             # (3 end)
      

      伪代码:

      if ( regex_find ( /^\$\{[^{}]+\}|\{\{[^{}]+\}\}/, value ) )
      {
          var found = false;
      
          while ( regex_search ( /^\$\{([^{}]+)\}|\{\{([^{}]+)\}\}|((?:(?!^\$\{[^{}]+\}|\{\{[^{}]+\}\})[\S\s])+)/g, match, value ) )
          {
              if ( match[1] != null )
              {
                  // Found '${..}' form
                  found = true;
                  var newNode = document.createElement("span");
                  newNode.setAttribute("ko-text", match[1]);
                  // Append newNode 
              }
              else
              if ( match[2] != null )
              {
                  // Found '{{..}}' form
                  found = true;
                  var newNode = document.createElement("span");
                  newNode.setAttribute("ko-text", match[2]);
                  // Append newNode 
              }
              else
              if ( match[3] != null )
              {
                  // Found '...' normal text
                  found = true;
                  var newNode = document.createTextNode( match[3] );
                  // Append newNode 
              }
          }
      
          if ( found )
          {
              // Clear or delete the original text node
              // ... 
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2011-12-16
        • 1970-01-01
        • 1970-01-01
        • 2021-09-04
        • 2020-10-16
        • 1970-01-01
        • 1970-01-01
        • 2017-10-18
        相关资源
        最近更新 更多