使用基于正则表达式的新DOM节点替换TextNode中的文本

时间:2015-07-08 14:21:45

标签: javascript html regex dom knockout.js

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

目的主要是执行一些插值或字符串模板化。

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

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

这一切都有效。

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

像这样:

<span ko-text="foo" />的{​​p> ${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是一个自定义函数。

3 个答案:

答案 0 :(得分:0)

Disclaimer: I don't know JavaScript! This is just a suggestion.

 #  /^\$\{([^{}]+)\}|\{\{([^{}]+)\}\}|((?:(?!^\$\{[^{}]+\}|\{\{[^{}]+\}\})[\S\s])+)/

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

Pseudo-code:

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
        // ... 
    }
}

答案 1 :(得分:0)

经过多次考虑后,我就是这样解决的:

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;
}

当然可以改善。

答案 2 :(得分:0)

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>