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

Javascript 使用基于正则表达式的新DOM节点替换TextNode中的文本,javascript,html,regex,dom,knockout.js,Javascript,Html,Regex,Dom,Knockout.js,我有一个函数可以预处理HTMLDOM中的文本节点 其目的基本上是执行一些插值或字符串模板 该函数基本上检查与正则表达式/\${([^}]*)}/g和/{([^}]*)}/g匹配的事件 示例:${foo+1}和{{{foo+2}} 这一切都在起作用 但我的目标是用新节点(例如,span)替换这些事件,这些节点由包含正则表达式中匹配项的内部值的敲除绑定表达式组成。位置正确。保留出现的空白 像这样: 用于${foo}(注意:自定义绑定语法) 我就是不能用TextNode.splitText来绕着它转

我有一个函数可以预处理HTMLDOM中的文本节点

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

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

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

这一切都在起作用

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

像这样:

用于
${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!这只是一个建议

 #  /^\$\{([^{}]+)\}|\{\{([^{}]+)\}\}|((?:(?!^\$\{[^{}]+\}|\{\{[^{}]+\}\})[\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
        // ... 
    }
}

免责声明:我不懂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
        // ... 
    }
}

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

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

当然可以改进。

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

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;
}
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);
}
当然可以改进

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结束

开始asdf结束


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