|
226 | 226 | window.ViewImage && ViewImage.init('.ebook img,a.zoom'); |
227 | 227 | }); |
228 | 228 | function ensureTcomment() { |
229 | | - var tcomment = document.getElementById('tcomment'); |
230 | | - if (tcomment) return tcomment; |
| 229 | + // 先确保只有一个 tcomment 容器 |
| 230 | + removeAllTcomment(); |
231 | 231 | var a = Docsify.dom; |
232 | 232 | var n = a.create("div"); |
233 | 233 | n.id = "tcomment"; |
234 | | - a.appendTo(a.find(".content"), n); |
| 234 | + var content = a.find(".content"); |
| 235 | + if (content) { |
| 236 | + a.appendTo(content, n); |
| 237 | + } |
235 | 238 | return n; |
236 | 239 | } |
237 | 240 |
|
238 | 241 | function removeAllTcomment() { |
| 242 | + // 移除所有 #tcomment 容器 |
239 | 243 | var nodes = document.querySelectorAll('#tcomment'); |
240 | 244 | for (var i = 0; i < nodes.length; i++) { |
241 | 245 | if (nodes[i] && nodes[i].parentNode) { |
242 | 246 | nodes[i].parentNode.removeChild(nodes[i]); |
243 | 247 | } |
244 | 248 | } |
| 249 | + // 同时移除 Twikoo 可能创建的弹窗/遮罩等全局元素 |
| 250 | + var tkModals = document.querySelectorAll('.tk-lightbox, .tk-action-icon__dialog, .tk-image-viewer'); |
| 251 | + for (var j = 0; j < tkModals.length; j++) { |
| 252 | + if (tkModals[j] && tkModals[j].parentNode) { |
| 253 | + tkModals[j].parentNode.removeChild(tkModals[j]); |
| 254 | + } |
| 255 | + } |
| 256 | + } |
| 257 | + |
| 258 | + // 全局销毁函数,用于页面切换前彻底清理 |
| 259 | + function destroyTwikoo() { |
| 260 | + // 停止所有定时器和观察者 |
| 261 | + if (twikooTimer) { |
| 262 | + clearTimeout(twikooTimer); |
| 263 | + twikooTimer = null; |
| 264 | + } |
| 265 | + if (twikooObserver) { |
| 266 | + twikooObserver.disconnect(); |
| 267 | + twikooObserver = null; |
| 268 | + } |
| 269 | + twikooLoading = false; |
| 270 | + // 彻底移除评论容器 |
| 271 | + removeAllTcomment(); |
245 | 272 | } |
246 | 273 |
|
247 | 274 | function normalizeCommentPath(path) { |
|
257 | 284 |
|
258 | 285 | // 动态插入 div#tcomment 的 dom |
259 | 286 | hook.mounted(function () { |
260 | | - ensureTcomment(); |
| 287 | + // 初始化时不创建,等 doneEach 再创建 |
| 288 | + }) |
| 289 | + |
| 290 | + // 页面开始切换时(路由变化前)清理 |
| 291 | + hook.beforeEach(function(content) { |
| 292 | + destroyTwikoo(); |
| 293 | + return content; |
261 | 294 | }) |
262 | 295 |
|
263 | 296 | // twikoo 初始化控制变量 |
|
270 | 303 | function loadTwikoo(path, token) { |
271 | 304 | if (token !== twikooToken) return; |
272 | 305 | if (twikooLoading) return; |
| 306 | + |
| 307 | + // 检查是否已有评论容器 |
| 308 | + var tcomment = document.getElementById('tcomment'); |
| 309 | + if (!tcomment) return; |
| 310 | + |
273 | 311 | twikooLoading = true; |
274 | | - var tcomment = ensureTcomment(); |
275 | | - if (tcomment) { |
276 | | - tcomment.innerHTML = ''; |
277 | | - } |
| 312 | + tcomment.innerHTML = ''; |
| 313 | + |
278 | 314 | twikoo.init({ |
279 | 315 | envId: 'https://twikooeo.sicnuwiki.com', |
280 | 316 | el: '#tcomment', |
|
286 | 322 | }).then(function () { |
287 | 323 | if (token !== twikooToken) return; |
288 | 324 | twikooLoading = false; |
289 | | - // 可选:强制刷新一次,确保切换页面后评论更新 |
290 | | - setTimeout(function () { |
291 | | - var tkIcon = document.getElementsByClassName("tk-icon")[0]; |
292 | | - if (tkIcon) tkIcon.click(); |
293 | | - }, 200); |
294 | 325 | }).catch(function () { |
295 | 326 | twikooLoading = false; |
296 | 327 | }); |
|
306 | 337 | twikooTimer = null; |
307 | 338 | } |
308 | 339 |
|
309 | | - var tcomment = ensureTcomment(); |
| 340 | + var tcomment = document.getElementById('tcomment'); |
310 | 341 | if (!tcomment) return; |
311 | 342 |
|
312 | 343 | if (!('IntersectionObserver' in window)) { |
|
334 | 365 |
|
335 | 366 | // 调用 twikoo 评论,正则 path,刷新当前评论 |
336 | 367 | hook.doneEach(function () { |
| 368 | + // ★★★ 第一步:立即彻底销毁旧的 Twikoo 实例和容器 ★★★ |
| 369 | + destroyTwikoo(); |
| 370 | + |
337 | 371 | // 获取当前 docsify 页面路径作为评论区分标识 |
338 | 372 | var currentPath = normalizeCommentPath(vm.route.path || location.hash.replace(/^#/, '').replace(/\?.*$/, '') || '/'); |
339 | 373 |
|
340 | | - // 如果路径相同,不重复初始化 |
341 | | - if (lastPath === currentPath) { |
342 | | - return; |
343 | | - } |
| 374 | + // 更新路径记录 |
344 | 375 | lastPath = currentPath; |
345 | 376 |
|
346 | 377 | // 切换页面时更新 token,避免旧请求回流渲染 |
347 | 378 | twikooToken += 1; |
| 379 | + var currentToken = twikooToken; |
348 | 380 | twikooLoading = false; |
349 | 381 |
|
350 | | - // 先清理旧容器,避免多个评论区叠加 |
351 | | - removeAllTcomment(); |
352 | | - var tcomment = ensureTcomment(); |
353 | | - if (tcomment) { |
354 | | - tcomment.innerHTML = ''; |
355 | | - } |
356 | | - |
357 | | - observeAndLoad(currentPath, twikooToken); |
| 382 | + // ★★★ 第二步:延迟创建新的评论容器,确保 DOM 已更新 ★★★ |
| 383 | + setTimeout(function() { |
| 384 | + // 检查 token 是否仍然有效(防止快速切换页面时的竞态条件) |
| 385 | + if (currentToken !== twikooToken) return; |
| 386 | + |
| 387 | + // 再次清理,确保没有残留 |
| 388 | + removeAllTcomment(); |
| 389 | + |
| 390 | + // 创建新的评论容器 |
| 391 | + var tcomment = ensureTcomment(); |
| 392 | + if (tcomment) { |
| 393 | + observeAndLoad(currentPath, currentToken); |
| 394 | + } |
| 395 | + }, 50); |
358 | 396 | }) |
359 | 397 | } |
360 | 398 | ] |
|
0 commit comments