iT邦幫忙

0

請問如何用標籤包住特定的文字而不影響在 innerHTML 的其他內容

  • 分享至 

  • xImage

你好,我想用 <mark> 標籤包住特定的文字,但當我使用 innerHTML 替換時,這方法會替換 <p> 標籤內的所有內容。

請問如何解決這個問題。

<p>
    <mark data-original-value="foobarABC">123</mark>
    ABC
</p>
const pTag = document.querySelector("p");
const pattern = new RegExp("ABC", "g");

pTag.innerHTML = pTag.innerHTML.replaceAll(pattern, `<mark>$&</mark>`);
console.log(pTag.outerHTML)

結果:

<p>
    <mark data-original-value="foobar<mark>ABC</mark>">123</mark>
    <mark>ABC</mark>
</p>

期望的結果:

<p>
    <mark data-original-value="foobarABC">123</mark>
    <mark>ABC</mark>
</p>
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中
4
neil_0221
iT邦新手 5 級 ‧ 2022-09-13 10:02:40
最佳解答

利用childNodes去取得子節點
第一個if是將空行子節點及有標籤的濾掉並把條件符合的字串加入變數newinerrHTNL
第二個if把有標籤的html加入變數newinerrHTNL裡面

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <p>
        <mark data-original-value="foobarABC">123</mark>
        ABC
        ABCDCDA
    </p>
    <script>
        const pTag = document.querySelector("p");
        const pTags = document.querySelector("p").childNodes;
        let newinerrHTNL = "";
        for (let i = 0; i < pTags.length; i++) {
            if (pTags[i].tagName == undefined && pTags[i].textContent != "") {
                const pattern = new RegExp("ABC", "g");
                newinerrHTNL += pTags[i].textContent.replaceAll(pattern, `<mark>$&</mark>`);
            } else if (pTags[i].tagName != undefined) {
                newinerrHTNL += pTags[i].outerHTML;
            }
        }
        pTag.innerHTML = newinerrHTNL;
    </script>
</body>

</html>

第二個寫法是包含若p裡面有其他標籤如span

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <p>
        <mark data-original-value="foobarABC">123</mark>
        ABC
        ABCDCDA
        <span>ABCDDDCCC</span>
    </p>
    <script>
        const pTag = document.querySelector("p");
        const pTags = document.querySelector("p").childNodes;
        let newinerrHTNL = "";
        for (let i = 0; i < pTags.length; i++) {
            if (pTags[i].textContent != "") {
                const pattern = new RegExp("ABC", "g");
                let replacetext = pTags[i].textContent.replaceAll(pattern, `<mark>$&</mark>`);
                if (pTags[i].tagName != undefined) {
                    pTags[i].innerHTML = replacetext;
                    newinerrHTNL += pTags[i].outerHTML;
                } else {
                    newinerrHTNL += replacetext;
                }

            }
        }
        pTag.innerHTML = newinerrHTNL;
    </script>
</body>

</html>
yaekiou iT邦新手 5 級 ‧ 2022-09-13 12:45:51 檢舉

謝謝

2
企鵝大叔
iT邦新手 5 級 ‧ 2022-09-13 10:03:37

因為您用的是 原生語法,所以我這邊也提供原生語法範例

方案1: 遍巡子節點, 符合期望, 產生標籤元素<mark>, 替換節點

<script>
// 取得指定標籤的子節點
var i, child_p = document.querySelector('p').childNodes;

// 跑迴圈對子節點進行確認
for (i = 0; i < child_p.length; i++) {
	// 空白的內文 => 跳過
	if (child_p[i].textContent.trim() === '') {
		continue;
	}
	// 有html標籤屬性 => 跳過
	if (child_p[i].tagName !== undefined) {
		continue;
	}
	// 文字內容是否匹配期望規則
	if (/ABC/g.test(child_p[i].textContent)) {
		// 建立新的 HTML標籤元素
		var new_mark = document.createElement('mark')
		// 帶入內容
		new_mark.innerHTML = child_p[i].textContent;
		// 替換子節點
		child_p[i].parentNode.replaceChild(new_mark, child_p[i]);
	}
}
</script>

方案2: 透過正則匹配, 只取出符合期望的 ABC

<script>
// 取得指定標籤的內文
var inner_p = document.querySelector('p').innerHTML;
// 建立匹配規則
var regex = new RegExp(".*ABC", "g");
// 取得匹配結果
var match = inner_p.match(regex);

var i, replace_arr = [];
// 跑迴圈確認匹配結果內容
for (i = 0; i < match.length; i++) {
	// 略過內容含有 < "
	if (/[\<|\"].*/.test(match[i])) {
		continue;
	}
	// 將期望取代的內文和期望取代的轉換結果放入替換陣列 replace
	replace_arr.push({
		'find': match[i],
		'replace': match[i].replaceAll(regex, `<mark>$&</mark>`)
	});
}

// 開始替換
for (i = 0; i < replace_arr.length; i++) {
	inner_p = inner_p.replace(replace_arr[i]['find'], replace_arr[i]['replace'])
}

// 替換內文結果
document.querySelector('p').innerHTML = inner_p;
</script>
yaekiou iT邦新手 5 級 ‧ 2022-09-13 13:04:26 檢舉

謝謝你的回答,首先抱歉我沒有詳細說明我的問題,第二是我只嘗試了

方案1: 遍巡子節點, 符合期望, 產生標籤元素, 替換節點

如果 ABC 前面有其他文字

<p>
    <mark data-original-value="foobarABC">123</mark>
    cccABC
</p>

方案1 得到的結果會是

<p>
    <mark data-original-value="foobarABC">123</mark>
    <mark>ABC</mark>
</p>

實際上我想要的結果是

<p>
    <mark data-original-value="foobarABC">123</mark>
    ccc<mark>ABC</mark>
</p>

抱歉我沒有詳細說明我的問題,謝謝你的回答

0
hahaha
iT邦新手 5 級 ‧ 2022-09-20 11:13:06

用有限状态机

我要發表回答

立即登入回答