簡體   English   中英

使用 JavaScript 將 HTML 插入文本節點

[英]Insert HTML into text node with JavaScript

我有一個小文本節點:

var node

我想在每次出現的“lol”周圍加上一個跨度。

node.nodeValue = node.nodeValue.replace(/lol/, "<span>lol</span>")

當我想要"lol"作為跨度元素時,它會打印出"<span>lol<span>"

Andreas Josas 給出的答案相當不錯。 然而,當搜索詞在同一個文本節點中出現多次時,代碼有幾個錯誤。 這是修復了這些錯誤的解決方案,此外,插入被分解為 matchText 以便於使用和理解。 現在只有新標簽在回調中構造並通過返回傳遞回 matchText。

更新了帶有錯誤修復的 matchText 函數:

var matchText = function(node, regex, callback, excludeElements) { 

    excludeElements || (excludeElements = ['script', 'style', 'iframe', 'canvas']);
    var child = node.firstChild;

    while (child) {
        switch (child.nodeType) {
        case 1:
            if (excludeElements.indexOf(child.tagName.toLowerCase()) > -1)
                break;
            matchText(child, regex, callback, excludeElements);
            break;
        case 3:
            var bk = 0;
            child.data.replace(regex, function(all) {
                var args = [].slice.call(arguments),
                    offset = args[args.length - 2],
                    newTextNode = child.splitText(offset+bk), tag;
                bk -= child.data.length + all.length;

                newTextNode.data = newTextNode.data.substr(all.length);
                tag = callback.apply(window, [child].concat(args));
                child.parentNode.insertBefore(tag, newTextNode);
                child = newTextNode;
            });
            regex.lastIndex = 0;
            break;
        }

        child = child.nextSibling;
    }

    return node;
};

用法:

matchText(document.getElementsByTagName("article")[0], new RegExp("\\b" + searchTerm + "\\b", "g"), function(node, match, offset) {
    var span = document.createElement("span");
    span.className = "search-term";
    span.textContent = match;
    return span;
});

如果您希望插入錨(鏈接)標簽而不是 span 標簽,請將 create 元素更改為“a”而不是“span”,添加一行以將 href 屬性添加到標簽,並將“a”添加到 excludeElements列表,以便不會在鏈接內創建鏈接。

以下文章為您提供了用 HTML 元素替換文本的代碼:

http://blog.alexanderdickson.com/javascript-replacing-text

來自文章:

var matchText = function(node, regex, callback, excludeElements) { 

    excludeElements || (excludeElements = ['script', 'style', 'iframe', 'canvas']);
    var child = node.firstChild;

    do {
        switch (child.nodeType) {
        case 1:
            if (excludeElements.indexOf(child.tagName.toLowerCase()) > -1) {
                continue;
            }
            matchText(child, regex, callback, excludeElements);
            break;
        case 3:
           child.data.replace(regex, function(all) {
                var args = [].slice.call(arguments),
                    offset = args[args.length - 2],
                    newTextNode = child.splitText(offset);

                newTextNode.data = newTextNode.data.substr(all.length);
                callback.apply(window, [child].concat(args));
                child = newTextNode;
            });
            break;
        }
    } while (child = child.nextSibling);

    return node;
}

用法:

matchText(document.getElementsByTagName("article")[0], new RegExp("\\b" + searchTerm + "\\b", "g"), function(node, match, offset) {
    var span = document.createElement("span");
    span.className = "search-term";
    span.textContent = match;
    node.parentNode.insertBefore(span, node.nextSibling); 
});

以及解釋:

本質上,正確的做法是……

  1. 遍歷所有文本節點。
  2. 在文本節點中查找子字符串。
  3. 在偏移處拆分它。
  4. 在拆分之間插入一個 span 元素。

不是說這是一個更好的答案,但我發布了我為完整性所做的事情。 就我而言,我已經查找或確定了我需要在特定 #text 節點中突出顯示的文本的偏移量。 這也闡明了步驟。

//node is a #text node, startIndex is the beginning location of the text to highlight, and endIndex is the index of the character just after the text to highlight     

var parentNode = node.parentNode;

// break the node text into 3 parts: part1 - before the selected text, part2- the text to highlight, and part3 - the text after the highlight
var s = node.nodeValue;

// get the text before the highlight
var part1 = s.substring(0, startIndex);

// get the text that will be highlighted
var part2 = s.substring(startIndex, endIndex);

// get the part after the highlight
var part3 = s.substring(endIndex);

// replace the text node with the new nodes
var textNode = document.createTextNode(part1);
parentNode.replaceChild(textNode, node);

// create a span node and add it to the parent immediately after the first text node
var spanNode = document.createElement("span");
spanNode.className = "HighlightedText";
parentNode.insertBefore(spanNode, textNode.nextSibling);

// create a text node for the highlighted text and add it to the span node
textNode = document.createTextNode(part2);
spanNode.appendChild(textNode);

// create a text node for the text after the highlight and add it after the span node
textNode = document.createTextNode(part3);
parentNode.insertBefore(textNode, spanNode.nextSibling);

您可能需要node作為父節點,這樣您就可以使用 innerHTML:

node.innerHTML=node.childNodes[0].nodeValue.replace(/lol/, "<span>lol</span>");

這里node.childNodes[0]指的是實際的文本節點, node是它的包含元素。

對於現在發現此問題的人的最新答案如下:

function textNodeInnerHTML(textNode,innerHTML) {
    var div = document.createElement('div');
    textNode.parentNode.insertBefore(div,textNode);
    div.insertAdjacentHTML('afterend',innerHTML);
    div.remove();
    textNode.remove();
}

這個想法是在textNode之前插入一個新創建的 html 元素(比如說var div = document.createElement('div'); ),使用:

textNode.parentNode.insertBefore(div,textNode);

然后使用:

div.insertAdjacentHTML(
 'afterend',
 textNode.data.replace(/lol/g,`<span style="color : red">lol</span>`)
) 

然后刪除textNodediv使用:

textNode.remove();
div.remove();

insertAdjacentHTML不會像innerHTML那樣破壞事件偵聽器。

如果要查找所有屬於elm后代的文本節點,請使用:

[...elm.querySelectorAll('*')]
.map(l => [...l.childNodes])
.flat()
.filter(l => l.nodeType === 3);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM