你好,我想用 <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>
利用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>
因為您用的是 原生語法,所以我這邊也提供原生語法範例
方案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>
謝謝你的回答,首先抱歉我沒有詳細說明我的問題,第二是我只嘗試了
方案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>
抱歉我沒有詳細說明我的問題,謝謝你的回答