Skip to content

Commit c9ddcdb

Browse files
authored
Merge pull request #3429 from LooseLi/fix-spoiler-text
fix: spoiler隐藏文本失效
2 parents a0b5474 + 4309a60 commit c9ddcdb

File tree

1 file changed

+65
-9
lines changed

1 file changed

+65
-9
lines changed

public/js/spoilerText.js

Lines changed: 65 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,31 @@
1+
/**
2+
* 转义正则表达式中的特殊字符
3+
* @param {string} string 需要转义的字符串
4+
* @returns {string} 转义后的字符串
5+
*/
6+
function escapeRegExp(string) {
7+
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
8+
}
9+
110
/**
211
* 将Node文本中的指定标签内容转换为带有指定类名的span
312
* @param regex
413
* @param node
514
* @param className
615
*/
716
function convertTextToSpoilerSpan(regex, node, className) {
8-
const wholeText = node.wholeText
17+
// 使用 textContent 替代 wholeText 以确保类型安全
18+
const textContent = node.textContent
919
let outerSpan = document.createElement('span')
1020
const fragments = []
1121
let lastIndex = 0
1222
let match
13-
while ((match = regex.exec(wholeText)) !== null) {
14-
console.log('符合要求的文字' + wholeText)
23+
while ((match = regex.exec(textContent)) !== null) {
24+
console.log('符合要求的文字' + textContent)
1525
// 添加前面未匹配的部分
1626
if (match.index > lastIndex) {
1727
outerSpan.appendChild(
18-
document.createTextNode(wholeText.slice(lastIndex, match.index))
28+
document.createTextNode(textContent.slice(lastIndex, match.index))
1929
)
2030
}
2131

@@ -31,8 +41,10 @@ function convertTextToSpoilerSpan(regex, node, className) {
3141
}
3242
if (outerSpan.childNodes.length) {
3343
// 添加剩余未匹配的部分
34-
if (lastIndex < wholeText.length) {
35-
outerSpan.appendChild(document.createTextNode(wholeText.slice(lastIndex)))
44+
if (lastIndex < textContent.length) {
45+
outerSpan.appendChild(
46+
document.createTextNode(textContent.slice(lastIndex))
47+
)
3648
}
3749
node.replaceWith(outerSpan)
3850
}
@@ -48,9 +60,12 @@ function processTextNodes(root, className, spoilerTag) {
4860
const regex = new RegExp(`${spoilerTag}(.*?)${spoilerTag}`, 'g')
4961
const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, {
5062
acceptNode: function (node) {
51-
return regex.test(node.wholeText)
52-
? NodeFilter.FILTER_ACCEPT
53-
: NodeFilter.FILTER_REJECT
63+
if (node.nodeType === Node.TEXT_NODE) {
64+
return regex.test(node.textContent)
65+
? NodeFilter.FILTER_ACCEPT
66+
: NodeFilter.FILTER_REJECT
67+
}
68+
return NodeFilter.FILTER_REJECT
5469
}
5570
})
5671
const waitProcessNodes = []
@@ -61,6 +76,47 @@ function processTextNodes(root, className, spoilerTag) {
6176
for (const waitProcessNode of waitProcessNodes) {
6277
convertTextToSpoilerSpan(regex, waitProcessNode, className)
6378
}
79+
80+
// 处理跨节点的 spoiler 标记
81+
processCrossNodeSpoilers(root, className, spoilerTag)
82+
}
83+
84+
/**
85+
* 处理跨节点的 spoiler 标记
86+
* @param {Element} root 要处理的根元素
87+
* @param {string} className 应用于 spoiler 内容的类名
88+
* @param {string} spoilerTag spoiler 标记符号
89+
*/
90+
function processCrossNodeSpoilers(root, className, spoilerTag) {
91+
if (root.nodeType !== Node.ELEMENT_NODE) return
92+
93+
const html = root.innerHTML
94+
95+
// 处理原始标签,如果是已经转义过的,则去除转义
96+
let originalTag = spoilerTag
97+
if (spoilerTag.startsWith('\\') || spoilerTag.includes('\\[')) {
98+
originalTag = spoilerTag.replace(/\\/g, '')
99+
}
100+
101+
// 创建正则表达式,直接匹配原始标签
102+
const regex = new RegExp(`\\${originalTag}([\\s\\S]*?)\\${originalTag}`, 'g')
103+
104+
const hasMatch = regex.test(html)
105+
106+
if (!hasMatch) return
107+
108+
// 重置正则表达式
109+
regex.lastIndex = 0
110+
111+
// 替换匹配项
112+
const newHtml = html.replace(regex, function (match, content) {
113+
return `<span class="${className}">${content}</span>`
114+
})
115+
116+
// 如果内容有变化,更新 DOM
117+
if (newHtml !== html) {
118+
root.innerHTML = newHtml
119+
}
64120
}
65121

66122
/**

0 commit comments

Comments
 (0)