【问题标题】:Loop through all nodes and wrap each word in a span if that word exists in a terms array如果单词存在于术语数组中,则遍历所有节点并将每个单词包装在一个跨度中
【发布时间】:2021-11-11 09:33:54
【问题描述】:

我正在尝试遍历所有 nodes 并检查该节点是否包含 terms 数组中的任何项目并将这些单词包装到 span 标签中。

function getAllTextNodes(element) {
  let node;
  let nodes = [];
  let walk = document.createTreeWalker(element,NodeFilter.SHOW_TEXT,null,false);
  while (node = walk.nextNode()) nodes.push(node);
  return nodes;
}

const editor = document.getElementById('editor');
const allNodes = getAllTextNodes(editor);
const terms = [
    {
        "id": 1,
        "definition": "A knowledge base is a published collection of documentation that typically includes answers to frequently asked questions, how-to guides, and troubleshooting",
        "expression": "knowledge base",
    },
    {
        "id": 2,
        "definition": "Knowledge management (KM) is the process of creating, sharing, using and managing the knowledge and information of an organization",
        "expression": "knowledge management",
    },
    {
        "id": 3,
        "definition": "this is test",
        "expression": "base",
    },
    {
        "id": 4,
        "definition": "management glossary item test",
        "expression": "management",
    },
    {
        "id": 5,
        "definition": "test",
        "expression": "Knowledge",
    }
]

allNodes.forEach(node => {
      if (node.parentNode !== null) {
        // Create New Node
        let newNode = document.createElement('p');
        newNode.innerHTML = node.parentNode.innerHTML;
        for (const term of terms) {
          if (node.textContent.toLowerCase().includes(term.expression.toLowerCase())) {
            const termNames = newNode.textContent.match(new RegExp("\\b" + term.expression + "\\b", "ig"))
            if (termNames !== null) {
              termNames.forEach((name, index) => {
                newNode.innerHTML = newNode.innerHTML.replace(newNode.textContent.match(new RegExp("\\b" + term.expression + "\\b", "ig"))[index], `<span class='hj-glossary-item' data-definition='${term.definition}' data-id='${term.id}'>${name}</span>`)
              })
            }
          }
        }
        // Update Node
        node.parentNode.innerHTML = newNode.innerHTML;
      }
    })
<div id="editor">
  <p>Management is the reason why knowledge management is important. Knowledge base is also important to base.</p>

<p>Management is the reason why knowledge management is important. Knowledge base is also important to base.</p>

<p>Management is the reason why knowledge management is important. Knowledge base is also important to base.</p>
</div>

【问题讨论】:

    标签: javascript arrays regex


    【解决方案1】:

    避免直接操作 HTML,因为您可能会更改标签本身(属性、...等)而不仅仅是文本。

    你可以:

    • 创建一个以查找表达式为键的映射(小写),并将术语对象作为值。按表达式的长度降序排列,使较长的表达式优先于较短的表达式。
    • 创建一个正则表达式来查找所有表达式(使用|)。
    • 通过匹配(也包括匹配)分割文本节点的文本
    • 迭代这些以构建新节点的文档片段,这将是 span 元素(用于匹配)和文本节点(用于中间文本)的混合
    • 用此片段替换原始文本节点。

    这是该想法的实现:

    function getAllTextNodes(element) {
      let node;
      let nodes = [];
      let walk = document.createTreeWalker(element,NodeFilter.SHOW_TEXT,null,false);
      while (node = walk.nextNode()) nodes.push(node);
      return nodes;
    }
    
    const terms = [{"id": 1,"definition": "A knowledge base is a published collection of documentation that typically includes answers to frequently asked questions, how-to guides, and troubleshooting","expression": "knowledge base",},{"id": 2,"definition": "Knowledge management (KM) is the process of creating, sharing, using and managing the knowledge and information of an organization","expression": "knowledge management",},{"id": 3,"definition": "this is test","expression": "base",},{"id": 4,"definition": "management glossary item test","expression": "management",},{"id": 5,"definition": "test","expression": "Knowledge",}]
    
    const termMap = new Map(
        [...terms].sort((a, b) => b.expression.length - a.expression.length)
                  .map(term => [term.expression.toLowerCase(), term])
    );
    const regex = RegExp("\\b(" + Array.from(termMap.keys()).join("|") + ")\\b", "ig");
    
    for (const node of getAllTextNodes(document.getElementById('editor'))) {
        const pieces = node.textContent.split(regex).filter(Boolean);
        if (!pieces.length) continue;
        const fragment = new DocumentFragment();
        for (const piece of pieces) {
            const term = termMap.get(piece.toLowerCase());
            if (term) {
                const newNode = document.createElement('span');
                newNode.className = 'hj-glossary-item';
                newNode.dataset.definition = term.definition;
                newNode.dataset.id = term.id;
                newNode.textContent = piece; // or = term.expression, if capitalisation must change
                fragment.append(newNode);
            } else {
                fragment.append(document.createTextNode(piece));
            }
        }
        node.replaceWith(fragment);
    }
    .hj-glossary-item { background: yellow }
    <div id="editor">
    <p>Management is the reason why knowledge management is important. Knowledge base is also important to base.</p>
    <p>Management is the reason why knowledge management is important. Knowledge base is also important to base.</p>
    <p>Management is the reason why knowledge management is important. Knowledge base is also important to base.</p>
    </div>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-12
      • 2014-09-07
      • 1970-01-01
      • 2016-11-11
      • 2012-03-08
      相关资源
      最近更新 更多