JQuery / Javascript - Поиск DOM для текста и вставка HTML - PullRequest
6 голосов
/ 20 декабря 2010

Как мне найти в DOM определенную строку в тексте документа (скажем, «сыр»), а затем вставить сразу HTML-код после этой строки (скажем, « фантастика »).

Я пробовал следующее:

for (var tag in document.innerHTML) {
    if (tag.matches(/cheese/) != undefined) {
        document.innerHTML.append(<b>is fantastic</b>
    }
}

(Выше приведено больше иллюстрации того, что я пробовал, а не фактического кода. Я предполагаю, что синтаксис ужасно неправильный, поэтому, пожалуйста, извините за любые ошибки, они не проблема).

Ура,

Пит

Ответы [ 6 ]

9 голосов
/ 20 декабря 2010

Существуют собственные методы поиска текста внутри документа:

MSIE: textRange.findText ()
Другие: window.find ()

Управлять данным textRange, если что-то было найдено.
Эти методы должны обеспечивать гораздо большую производительность, чем обход всего документа.

Пример:

<html>
<head>

  <script>
  function fx(a,b)
  {
    if(window.find)
    {
      while(window.find(a))
      {
        var node=document.createElement('b');
            node.appendChild(document.createTextNode(b));
        var rng=window.getSelection().getRangeAt(0);
            rng.collapse(false);
            rng.insertNode(node);
      }
    }
    else if(document.body.createTextRange)
    {
      var rng=document.body.createTextRange();
      while(rng.findText(a))
      {
        rng.collapse(false);
        rng.pasteHTML('<b>'+b+'</b>');
      }
    }
  }
  </script>
</head>
<body onload="fx('cheese','is wonderful')">
<p>I've made a wonderful cheesecake with some <i>cheese</i> from my <u>chees</u>e-factory!</p>
</body>
</html>
6 голосов
/ 20 декабря 2010

Это грубо и не способ сделать это, но;

document.body.innerHTML = document.body.innerHTML.replace(/cheese/, 'cheese <b>is fantastic</b>');
2 голосов
/ 20 декабря 2010

Вы можете использовать это с JQuery:

$('*:contains("cheese")').each(function (idx, elem) {
    var changed = $(elem).html().replace('cheese', 'cheese <b>is fantastic</b>');
    $(elem).html(changed);
});

Я не проверял это, но что-то в этом роде должно работать.

Обратите внимание, что * будет соответствовать всем элементам,даже html, поэтому вы можете использовать body *:contains(...), чтобы убедиться, что только элементы, являющиеся потомками тела документа, будут просмотрены.

0 голосов
/ 03 июня 2011

Работает во всех браузерах, кроме IE. Я думаю, что требуется подтверждение.

Это также поддерживает контент в iframes.

Обратите внимание, что другие примеры, которые я видел, такие как приведенный выше,RECURSIVE, который потенциально плох в javascript, который может закончиться переполнением стека, особенно в клиенте браузера, который имеет ограниченную память для таких вещей.Слишком много рекурсии может привести к тому, что javascript перестанет выполняться.

Если вы мне не верите, попробуйте примеры здесь себя ...

Если кто-то захочет внести свой вкладкод здесь .

function grepNodes(searchText, frameId) {
  var matchedNodes = [];
  var regXSearch;
  if (typeof searchText === "string") {
    regXSearch = new RegExp(searchText, "g");
  }
  else {
    regXSearch = searchText;
  } 
  var currentNode = null, matches = null;
  if (frameId && !window.frames[frameId]) {
    return null;
  }
  var theDoc = (frameId) ? window.frames[frameId].contentDocument : document;
  var allNodes = (theDoc.all) ? theDoc.all : theDoc.getElementsByTagName('*');
  for (var nodeIdx in allNodes) {
    currentNode = allNodes[nodeIdx];
    if (!currentNode.nodeName || currentNode.nodeName === undefined) {
      break;
    }
    if (!(currentNode.nodeName.toLowerCase().match(/html|script|head|meta|link|object/))) {
      matches = currentNode.innerText.match(regXSearch);
      var totalMatches = 0;
      if (matches) {
        var totalChildElements = 0;
        for (var i=0;i<currentNode.children.length;i++) {
          if (!(currentNode.children[i].nodeName.toLowerCase().match(/html|script|head|meta|link|object/))) {
            totalChildElements++;
          }
        }
        matchedNodes.push({node: currentNode, numMatches: matches.length, childElementsWithMatch: 0, nodesYetTraversed: totalChildElements});
      }
      for (var i = matchedNodes.length - 1; i >= 0; i--) {
        previousElement = matchedNodes[i - 1];
        if (!previousElement) {
          continue;
        }
        if (previousElement.nodesYetTraversed !== 0 && previousElement.numMatches !== previousElement.childElementsWithMatch) {
          previousElement.childElementsWithMatch++;
          previousElement.nodesYetTraversed--;
        }      
        else if (previousElement.nodesYetTraversed !== 0) {
          previousElement.nodesYetTraversed--;
        }               
      }
    }
  }
  var processedMatches = [];
  for (var i =0; i <  matchedNodes.length; i++) {
    if (matchedNodes[i].numMatches > matchedNodes[i].childElementsWithMatch) {
      processedMatches.push(matchedNodes[i].node);
    }
  }
  return processedMatches; 
};
0 голосов
/ 20 декабря 2010

Способ сделать это состоит в том, чтобы просмотреть документ и найти в каждом текстовом узле нужный текст.Любой способ с участием innerHTML безнадежно ошибочен.

Вот функция, которая работает во всех браузерах и рекурсивно обходит DOM в указанном узле и заменяет вхождения фрагмента текста узлами, скопированными из предоставленного узла шаблона replacementNodeTemplate:

function replaceText(node, text, replacementNodeTemplate) {
    if (node.nodeType == 3) {
        while (node) {
            var textIndex = node.data.indexOf(text), currentNode = node;
            if (textIndex == -1) {
                node = null;
            } else {
                // Split the text node after the text
                var splitIndex = textIndex + text.length;
                var replacementNode = replacementNodeTemplate.cloneNode(true);
                if (splitIndex < node.length) {
                    node = node.splitText(textIndex + text.length);
                    node.parentNode.insertBefore(replacementNode, node);
                } else {
                    node.parentNode.appendChild(replacementNode);
                    node = null;
                }
                currentNode.deleteData(textIndex, text.length);
            }
        }
    } else {
        var child = node.firstChild, nextChild;
        while (child) {
            nextChild = child.nextSibling;
            replaceText(child, text, replacementNodeTemplate);
            child = nextChild;
        }
    }
}

Вот пример использования:

replaceText(document.body, "cheese", document.createTextNode("CHEESE IS GREAT"));

Если вы предпочитаете, вы можете создать функцию-обертку, чтобы вместо нее указывать содержимое замены в виде строки HTML:

function replaceTextWithHtml(node, text, html) {
    var div = document.createElement("div");
    div.innerHTML = html;
    var templateNode = document.createDocumentFragment();
    while (div.firstChild) {
        templateNode.appendChild(div.firstChild);
    }
    replaceText(node, text, templateNode);
}

Пример:

replaceTextWithHtml(document.body, "cheese", "cheese <b>is fantastic</b>");

Я включил это в пример jsfiddle: http://jsfiddle.net/timdown/azZsa/

0 голосов
/ 20 декабря 2010

Пример решения:

<ul>
  <li>cheese</li>
  <li>cheese</li>
  <li>cheese</li>
</ul>

Коды запросов:

$('ul li').each(function(index) {
  if($(this).text()=="cheese")
  {
    $(this).text('cheese is fantastic');
  }
});
...