zhangdocs 1.1.29 → 1.1.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -53,7 +53,7 @@
53
53
  </div>
54
54
 
55
55
  <!-- 滚动到底部按钮 -->
56
- <button class="scroll-to-bottom" id="scroll-to-bottom" aria-label="滚动到底部" title="滚动到底部">
56
+ <button class="scroll-to-bottom" id="scroll-to-bottom" aria-label="滚动到底部" title="滚动到底部" onclick="(function(){var container=document.querySelector('.markdown-body')||document.querySelector('.warpper')||document.documentElement;container.scrollTop=container.scrollHeight;window.scrollTo(0,document.documentElement.scrollHeight);return false;})();">
57
57
  <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
58
58
  <path d="M6 9l6 6 6-6"></path>
59
59
  </svg>
@@ -103,6 +103,104 @@ style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background:
103
103
 
104
104
  // 标记为已初始化
105
105
  isInitialized = true;
106
+
107
+ function getDirectLink(li) {
108
+ if (!li || !li.children) {
109
+ return null;
110
+ }
111
+ for (var i = 0; i < li.children.length; i++) {
112
+ if (li.children[i].tagName === 'A') {
113
+ return li.children[i];
114
+ }
115
+ }
116
+ return li.querySelector('a');
117
+ }
118
+
119
+ function getDecodedTail(input) {
120
+ var tail = '';
121
+ try {
122
+ var parsed = new URL(input, window.location.origin);
123
+ tail = (parsed.pathname || '').split('/').pop() || '';
124
+ } catch (e) {
125
+ tail = String(input || '')
126
+ .split('#')[0]
127
+ .split('?')[0]
128
+ .split('/')
129
+ .pop() || '';
130
+ }
131
+ try {
132
+ return decodeURIComponent(tail);
133
+ } catch (e2) {
134
+ return tail;
135
+ }
136
+ }
137
+
138
+ function stripExt(name) {
139
+ return String(name || '').replace(/\.(html|md)$/i, '');
140
+ }
141
+
142
+ // 打开菜单时定位到当前页面,并高亮其父级目录路径
143
+ function locateCurrentMenuItem() {
144
+ var menuContent = menuPopup.querySelector('.menu-popup-content');
145
+ if (!menuContent) {
146
+ return;
147
+ }
148
+
149
+ var previousMarks = menuContent.querySelectorAll(
150
+ '.menu-current-item, .menu-current-link, .menu-ancestor-item'
151
+ );
152
+ previousMarks.forEach(function(node) {
153
+ node.classList.remove('menu-current-item');
154
+ node.classList.remove('menu-current-link');
155
+ node.classList.remove('menu-ancestor-item');
156
+ });
157
+
158
+ var currentLi = menuContent.querySelector('li.active');
159
+ if (!currentLi) {
160
+ // 回退:按当前 URL 匹配菜单项(兼容中文路径编码)
161
+ var currentTail = getDecodedTail(window.location.href);
162
+ var currentBase = stripExt(currentTail);
163
+ if (currentTail) {
164
+ var links = menuContent.querySelectorAll('a[href]');
165
+ for (var i = 0; i < links.length; i++) {
166
+ var linkTail = getDecodedTail(links[i].getAttribute('href'));
167
+ var linkBase = stripExt(linkTail);
168
+ if (linkTail === currentTail || linkBase === currentBase) {
169
+ currentLi = links[i].closest('li');
170
+ break;
171
+ }
172
+ }
173
+ }
174
+ }
175
+
176
+ if (!currentLi) {
177
+ return;
178
+ }
179
+
180
+ currentLi.classList.add('menu-current-item');
181
+ var currentLink = getDirectLink(currentLi);
182
+ if (currentLink) {
183
+ currentLink.classList.add('menu-current-link');
184
+ }
185
+
186
+ var parent = currentLi.parentElement;
187
+ while (parent && parent !== menuPopup) {
188
+ if (parent.tagName === 'LI') {
189
+ parent.classList.add('menu-ancestor-item');
190
+ }
191
+ parent = parent.parentElement;
192
+ }
193
+
194
+ try {
195
+ currentLi.scrollIntoView({
196
+ block: 'center',
197
+ inline: 'nearest'
198
+ });
199
+ } catch (e) {
200
+ // 兼容旧浏览器
201
+ currentLi.scrollIntoView();
202
+ }
203
+ }
106
204
 
107
205
  // 打开菜单
108
206
  function openMenu() {
@@ -110,6 +208,7 @@ style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background:
110
208
  menuPopup.classList.add('menu-popup-show');
111
209
  menuOverlay.classList.add('menu-overlay-show');
112
210
  document.body.style.overflow = 'hidden'; // 防止背景滚动
211
+ setTimeout(locateCurrentMenuItem, 50);
113
212
  }
114
213
 
115
214
  // 关闭菜单
@@ -177,20 +276,19 @@ style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background:
177
276
  // 菜单图标显示后,初始化菜单功能
178
277
  setTimeout(initMenuPopup, 50);
179
278
  }
180
- // 初始化滚动到底部按钮
279
+ // 初始化滚动到底部按钮 - 直接添加 show 类
181
280
  if (scrollToBottomBtn) {
182
- setTimeout(function() {
281
+ function addShowClass() {
183
282
  scrollToBottomBtn.style.display = 'flex';
184
- // 检查是否需要显示按钮
185
- setTimeout(function() {
186
- var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
187
- var scrollHeight = document.documentElement.scrollHeight;
188
- var clientHeight = document.documentElement.clientHeight;
189
- if (scrollHeight - scrollTop - clientHeight > 5) {
190
- scrollToBottomBtn.classList.add('show');
191
- }
192
- }, 200);
193
- }, 100);
283
+ scrollToBottomBtn.classList.add('show');
284
+ // 强制设置内联样式,确保显示
285
+ scrollToBottomBtn.style.opacity = '1';
286
+ scrollToBottomBtn.style.visibility = 'visible';
287
+ }
288
+ addShowClass();
289
+ setTimeout(addShowClass, 0);
290
+ setTimeout(addShowClass, 100);
291
+ setTimeout(addShowClass, 300);
194
292
  }
195
293
  }
196
294
  })();
@@ -242,22 +340,43 @@ style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background:
242
340
  // 菜单图标显示后,初始化菜单功能
243
341
  setTimeout(initMenuPopup, 50);
244
342
  }
245
- // 显示内容后,初始化滚动到底部按钮
246
- setTimeout(function() {
343
+ // 显示内容后,直接显示滚动到底部按钮 - 强制添加 show 类并设置内联样式
344
+ function addShowClass() {
247
345
  var scrollToBottomBtn = document.getElementById('scroll-to-bottom');
248
346
  if (scrollToBottomBtn) {
249
347
  scrollToBottomBtn.style.display = 'flex';
250
- // 检查是否需要显示按钮
251
- setTimeout(function() {
252
- var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
253
- var scrollHeight = document.documentElement.scrollHeight;
254
- var clientHeight = document.documentElement.clientHeight;
255
- if (scrollHeight - scrollTop - clientHeight > 5) {
256
- scrollToBottomBtn.classList.add('show');
257
- }
258
- }, 100);
348
+ scrollToBottomBtn.classList.add('show');
349
+ // 强制设置内联样式,确保显示
350
+ scrollToBottomBtn.style.opacity = '1';
351
+ scrollToBottomBtn.style.visibility = 'visible';
352
+ // 确保点击事件已绑定 - 使用多种方式
353
+ if (!scrollToBottomBtn.hasAttribute('data-click-bound')) {
354
+ var clickHandler = function(e) {
355
+ e.preventDefault();
356
+ e.stopPropagation();
357
+ var markdownBody = document.querySelector('.markdown-body');
358
+ var warpper = document.querySelector('.warpper');
359
+ var container = markdownBody || warpper || document.documentElement;
360
+ if (container) {
361
+ container.scrollTop = container.scrollHeight;
362
+ }
363
+ window.scrollTo(0, document.documentElement.scrollHeight);
364
+ return false;
365
+ };
366
+ scrollToBottomBtn.addEventListener('click', clickHandler, true); // 捕获阶段
367
+ scrollToBottomBtn.onclick = clickHandler; // 直接赋值
368
+ scrollToBottomBtn.setAttribute('data-click-bound', 'true');
369
+ }
259
370
  }
260
- }, 100);
371
+ }
372
+ // 立即执行
373
+ addShowClass();
374
+ // 多次执行,确保添加成功
375
+ setTimeout(addShowClass, 0);
376
+ setTimeout(addShowClass, 50);
377
+ setTimeout(addShowClass, 100);
378
+ setTimeout(addShowClass, 200);
379
+ setTimeout(addShowClass, 500);
261
380
  }
262
381
 
263
382
  // 隐藏内容
@@ -384,9 +503,277 @@ style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background:
384
503
  setTimeout(initMenuPopup, 500);
385
504
  setTimeout(initMenuPopup, 1000);
386
505
 
387
- // 图片预览功能初始化
506
+ // 图片/mermaid 预览功能初始化
388
507
  (function() {
389
508
  var imageViewer = null;
509
+ var imageViewerObserver = null;
510
+ var viewerRefreshTimer = null;
511
+ var mermaidPreviewModal = null;
512
+ var mermaidPreviewScale = 1;
513
+ var mermaidPreviewOffsetX = 0;
514
+ var mermaidPreviewOffsetY = 0;
515
+
516
+ function applyMermaidPreviewTransform(container) {
517
+ if (!container) {
518
+ return;
519
+ }
520
+ container.style.transform =
521
+ 'translate(' + mermaidPreviewOffsetX + 'px, ' + mermaidPreviewOffsetY + 'px) scale(' + mermaidPreviewScale + ')';
522
+ }
523
+
524
+ function scheduleInitImageViewer(delay) {
525
+ if (viewerRefreshTimer) {
526
+ clearTimeout(viewerRefreshTimer);
527
+ }
528
+ viewerRefreshTimer = setTimeout(function() {
529
+ initImageViewer();
530
+ }, typeof delay === 'number' ? delay : 80);
531
+ }
532
+
533
+ function ensureMermaidPreviewModal() {
534
+ if (mermaidPreviewModal) {
535
+ return mermaidPreviewModal;
536
+ }
537
+ var modal = document.createElement('div');
538
+ modal.id = 'mermaid-preview-modal';
539
+ modal.style.cssText = [
540
+ 'position:fixed',
541
+ 'inset:0',
542
+ 'display:none',
543
+ 'z-index:100010',
544
+ 'background:rgba(12,16,22,0.82)',
545
+ 'align-items:center',
546
+ 'justify-content:center',
547
+ 'padding:24px'
548
+ ].join(';');
549
+
550
+ var container = document.createElement('div');
551
+ container.className = 'mermaid-preview-container';
552
+ container.style.cssText = [
553
+ 'position:relative',
554
+ 'max-width:96vw',
555
+ 'max-height:92vh',
556
+ 'overflow:hidden',
557
+ 'background:#fff',
558
+ 'border-radius:10px',
559
+ 'padding:14px',
560
+ 'box-shadow:0 12px 36px rgba(0,0,0,0.35)',
561
+ 'transform-origin:center center',
562
+ 'transition:transform 0.08s linear'
563
+ ].join(';');
564
+
565
+ var closeBtn = document.createElement('button');
566
+ closeBtn.type = 'button';
567
+ closeBtn.innerHTML = '&times;';
568
+ closeBtn.setAttribute('aria-label', '关闭Mermaid预览');
569
+ closeBtn.style.cssText = [
570
+ 'position:absolute',
571
+ 'right:10px',
572
+ 'top:6px',
573
+ 'width:28px',
574
+ 'height:28px',
575
+ 'border:none',
576
+ 'border-radius:50%',
577
+ 'background:rgba(0,0,0,0.08)',
578
+ 'cursor:pointer',
579
+ 'font-size:20px',
580
+ 'line-height:1'
581
+ ].join(';');
582
+
583
+ var content = document.createElement('div');
584
+ content.className = 'mermaid-preview-content';
585
+ content.style.cssText = [
586
+ 'min-width:320px',
587
+ 'min-height:160px',
588
+ 'width:90vw',
589
+ 'height:82vh',
590
+ 'display:flex',
591
+ 'align-items:center',
592
+ 'justify-content:center',
593
+ 'overflow:hidden',
594
+ 'cursor:default'
595
+ ].join(';');
596
+
597
+ closeBtn.addEventListener('click', function() {
598
+ modal.style.display = 'none';
599
+ document.body.style.overflow = '';
600
+ mermaidPreviewScale = 1;
601
+ mermaidPreviewOffsetX = 0;
602
+ mermaidPreviewOffsetY = 0;
603
+ applyMermaidPreviewTransform(container);
604
+ });
605
+ modal.addEventListener('click', function(e) {
606
+ if (e.target === modal) {
607
+ modal.style.display = 'none';
608
+ document.body.style.overflow = '';
609
+ mermaidPreviewScale = 1;
610
+ mermaidPreviewOffsetX = 0;
611
+ mermaidPreviewOffsetY = 0;
612
+ applyMermaidPreviewTransform(container);
613
+ }
614
+ });
615
+ document.addEventListener('keydown', function(e) {
616
+ if (e.key === 'Escape' && modal.style.display !== 'none') {
617
+ modal.style.display = 'none';
618
+ document.body.style.overflow = '';
619
+ mermaidPreviewScale = 1;
620
+ mermaidPreviewOffsetX = 0;
621
+ mermaidPreviewOffsetY = 0;
622
+ applyMermaidPreviewTransform(container);
623
+ }
624
+ });
625
+
626
+ container.appendChild(closeBtn);
627
+ container.appendChild(content);
628
+ modal.appendChild(container);
629
+ document.body.appendChild(modal);
630
+ mermaidPreviewModal = modal;
631
+ return mermaidPreviewModal;
632
+ }
633
+
634
+ function bindMermaidPreview(markdownBody) {
635
+ var mermaidSvgs = markdownBody.querySelectorAll('.mermaid svg');
636
+ mermaidSvgs.forEach(function(svg) {
637
+ if (svg.getAttribute('data-mermaid-preview-bound') === 'true') {
638
+ return;
639
+ }
640
+ svg.setAttribute('data-mermaid-preview-bound', 'true');
641
+ svg.style.cursor = 'zoom-in';
642
+ svg.addEventListener('click', function(e) {
643
+ e.preventDefault();
644
+ e.stopPropagation();
645
+
646
+ var modal = ensureMermaidPreviewModal();
647
+ var content = modal.querySelector('.mermaid-preview-content');
648
+ var container = modal.querySelector('.mermaid-preview-container');
649
+ if (!content || !container) {
650
+ return;
651
+ }
652
+ content.innerHTML = '';
653
+
654
+ var clone = svg.cloneNode(true);
655
+ var vb = clone.getAttribute('viewBox');
656
+ var vbWidth = 0;
657
+ var vbHeight = 0;
658
+ if (vb) {
659
+ var parts = vb.trim().split(/\s+/);
660
+ if (parts.length === 4) {
661
+ vbWidth = parseFloat(parts[2]) || 0;
662
+ vbHeight = parseFloat(parts[3]) || 0;
663
+ }
664
+ }
665
+ if (!vbWidth || !vbHeight) {
666
+ var rect = svg.getBoundingClientRect();
667
+ vbWidth = rect.width || 800;
668
+ vbHeight = rect.height || 500;
669
+ }
670
+
671
+ var maxWidth = Math.floor(window.innerWidth * 0.9);
672
+ var maxHeight = Math.floor(window.innerHeight * 0.82);
673
+ var fitScale = Math.min(maxWidth / vbWidth, maxHeight / vbHeight);
674
+ if (!isFinite(fitScale) || fitScale <= 0) {
675
+ fitScale = 1;
676
+ }
677
+ // 预览默认尽量放大显示,但保留比例,避免文字过小
678
+ var defaultScale = Math.max(fitScale, 1.25);
679
+ var renderWidth = Math.round(vbWidth * defaultScale);
680
+ var renderHeight = Math.round(vbHeight * defaultScale);
681
+ if (renderWidth > maxWidth || renderHeight > maxHeight) {
682
+ var clampScale = Math.min(maxWidth / vbWidth, maxHeight / vbHeight);
683
+ renderWidth = Math.round(vbWidth * clampScale);
684
+ renderHeight = Math.round(vbHeight * clampScale);
685
+ }
686
+
687
+ clone.removeAttribute('width');
688
+ clone.removeAttribute('height');
689
+ clone.style.width = Math.max(320, renderWidth) + 'px';
690
+ clone.style.height = 'auto';
691
+ clone.style.maxWidth = '100%';
692
+ clone.style.maxHeight = '100%';
693
+ clone.style.display = 'block';
694
+ clone.style.cursor = 'grab';
695
+ clone.style.userSelect = 'none';
696
+ content.appendChild(clone);
697
+
698
+ // 改为缩放整个预览容器,不出现滚动条
699
+ if (content.__wheelZoomHandler) {
700
+ content.removeEventListener('wheel', content.__wheelZoomHandler, false);
701
+ }
702
+ var wheelZoomHandler = function(evt) {
703
+ evt.preventDefault();
704
+ var zoomStep = evt.deltaY < 0 ? 1.08 : 0.92;
705
+ mermaidPreviewScale = Math.max(0.8, Math.min(2.2, mermaidPreviewScale * zoomStep));
706
+ applyMermaidPreviewTransform(container);
707
+ };
708
+ content.addEventListener('wheel', wheelZoomHandler, { passive: false });
709
+ content.__wheelZoomHandler = wheelZoomHandler;
710
+
711
+ // 支持按住左键拖动(小手光标)
712
+ content.style.cursor = 'grab';
713
+ var isDragging = false;
714
+ var dragStartX = 0;
715
+ var dragStartY = 0;
716
+ var dragBaseX = 0;
717
+ var dragBaseY = 0;
718
+
719
+ if (content.__dragMouseDownHandler) {
720
+ content.removeEventListener('mousedown', content.__dragMouseDownHandler, false);
721
+ }
722
+ if (content.__dragMouseMoveHandler) {
723
+ window.removeEventListener('mousemove', content.__dragMouseMoveHandler, false);
724
+ }
725
+ if (content.__dragMouseUpHandler) {
726
+ window.removeEventListener('mouseup', content.__dragMouseUpHandler, false);
727
+ }
728
+
729
+ var dragMouseDownHandler = function(evt) {
730
+ if (evt.button !== 0) {
731
+ return;
732
+ }
733
+ isDragging = true;
734
+ dragStartX = evt.clientX;
735
+ dragStartY = evt.clientY;
736
+ dragBaseX = mermaidPreviewOffsetX;
737
+ dragBaseY = mermaidPreviewOffsetY;
738
+ content.style.cursor = 'grabbing';
739
+ clone.style.cursor = 'grabbing';
740
+ container.style.transition = 'none';
741
+ evt.preventDefault();
742
+ };
743
+ var dragMouseMoveHandler = function(evt) {
744
+ if (!isDragging) {
745
+ return;
746
+ }
747
+ mermaidPreviewOffsetX = dragBaseX + (evt.clientX - dragStartX);
748
+ mermaidPreviewOffsetY = dragBaseY + (evt.clientY - dragStartY);
749
+ applyMermaidPreviewTransform(container);
750
+ };
751
+ var dragMouseUpHandler = function() {
752
+ if (!isDragging) {
753
+ return;
754
+ }
755
+ isDragging = false;
756
+ content.style.cursor = 'grab';
757
+ clone.style.cursor = 'grab';
758
+ container.style.transition = 'transform 0.08s linear';
759
+ };
760
+
761
+ content.addEventListener('mousedown', dragMouseDownHandler, false);
762
+ window.addEventListener('mousemove', dragMouseMoveHandler, false);
763
+ window.addEventListener('mouseup', dragMouseUpHandler, false);
764
+ content.__dragMouseDownHandler = dragMouseDownHandler;
765
+ content.__dragMouseMoveHandler = dragMouseMoveHandler;
766
+ content.__dragMouseUpHandler = dragMouseUpHandler;
767
+
768
+ modal.style.display = 'flex';
769
+ document.body.style.overflow = 'hidden';
770
+ mermaidPreviewScale = 1;
771
+ mermaidPreviewOffsetX = 0;
772
+ mermaidPreviewOffsetY = 0;
773
+ applyMermaidPreviewTransform(container);
774
+ });
775
+ });
776
+ }
390
777
 
391
778
  function initImageViewer() {
392
779
  // 查找markdown-body容器
@@ -394,6 +781,20 @@ style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background:
394
781
  if (!markdownBody) {
395
782
  return;
396
783
  }
784
+
785
+ // 监听内容变化:mermaid 常常是异步渲染 SVG
786
+ if (!imageViewerObserver) {
787
+ imageViewerObserver = new MutationObserver(function() {
788
+ scheduleInitImageViewer(80);
789
+ });
790
+ imageViewerObserver.observe(markdownBody, {
791
+ childList: true,
792
+ subtree: true
793
+ });
794
+ }
795
+
796
+ // Mermaid 保持原始 SVG 渲染,点击时弹出预览(避免转图片导致文字裁切)
797
+ bindMermaidPreview(markdownBody);
397
798
 
398
799
  // 查找所有图片
399
800
  var images = markdownBody.querySelectorAll('img');
@@ -413,7 +814,7 @@ style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background:
413
814
  // 为图片添加样式和点击事件
414
815
  images.forEach(function(img) {
415
816
  // 跳过已经是链接内的图片
416
- if (img.parentElement.tagName === 'A') {
817
+ if (img.parentElement && img.parentElement.tagName === 'A') {
417
818
  return;
418
819
  }
419
820
 
@@ -426,11 +827,41 @@ style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background:
426
827
  try {
427
828
  imageViewer = new Viewer(markdownBody, {
428
829
  inline: false,
429
- viewed: function() {
430
- // 查看图片时的回调
431
- },
432
- hidden: function() {
433
- // 关闭查看器时的回调
830
+ viewed: function(event) {
831
+ // 仅对 Mermaid 图应用更大的默认缩放和白底,提升文字可读性
832
+ try {
833
+ var originalImage = event && event.detail && event.detail.originalImage;
834
+ var isMermaidImage = !!(
835
+ originalImage &&
836
+ originalImage.classList &&
837
+ originalImage.classList.contains('mermaid-preview-image')
838
+ );
839
+ if (!isMermaidImage || !imageViewer) {
840
+ return;
841
+ }
842
+
843
+ var imageData = imageViewer.imageData;
844
+ var viewerData = imageViewer.viewerData;
845
+ if (!imageData || !viewerData || !imageData.naturalWidth || !imageData.naturalHeight) {
846
+ return;
847
+ }
848
+
849
+ var fitRatio = Math.min(
850
+ viewerData.width / imageData.naturalWidth,
851
+ viewerData.height / imageData.naturalHeight
852
+ );
853
+ var targetRatio = Math.max(fitRatio * 1.2, 1.25);
854
+ imageViewer.zoomTo(targetRatio);
855
+
856
+ if (imageViewer.image) {
857
+ imageViewer.image.style.backgroundColor = '#ffffff';
858
+ imageViewer.image.style.padding = '14px';
859
+ imageViewer.image.style.borderRadius = '8px';
860
+ imageViewer.image.style.boxShadow = '0 6px 24px rgba(0, 0, 0, 0.25)';
861
+ }
862
+ } catch (e) {
863
+ console.error('Mermaid 预览缩放初始化失败:', e);
864
+ }
434
865
  },
435
866
  toolbar: {
436
867
  zoomIn: true,
@@ -464,6 +895,8 @@ style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background:
464
895
  // 延迟初始化(处理动态显示的情况)
465
896
  setTimeout(initImageViewer, 500);
466
897
  setTimeout(initImageViewer, 1000);
898
+ setTimeout(initImageViewer, 2000);
899
+ setTimeout(initImageViewer, 3500);
467
900
  })();
468
901
 
469
902
  // 上一节/下一节导航功能
@@ -491,54 +924,122 @@ style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background:
491
924
 
492
925
  // 滚动到底部功能
493
926
  (function() {
927
+ var scrollToBottomBtn = null;
928
+ var mainContainer = null;
929
+ var isInitialized = false;
930
+
931
+ // 检查是否在页面底部
932
+ function isAtBottom() {
933
+ var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
934
+ var scrollHeight = document.documentElement.scrollHeight;
935
+ var clientHeight = document.documentElement.clientHeight;
936
+ // 允许5px的误差
937
+ return scrollHeight - scrollTop - clientHeight <= 5;
938
+ }
939
+
940
+ // 显示/隐藏按钮
941
+ function toggleButton() {
942
+ if (!scrollToBottomBtn) {
943
+ return;
944
+ }
945
+
946
+ // 确保按钮可见(如果内容已显示)
947
+ if (mainContainer && mainContainer.style.display !== 'none') {
948
+ scrollToBottomBtn.style.display = 'flex';
949
+
950
+ // 直接添加 show 类,让按钮显示
951
+ // 只有在页面底部时才移除 show 类
952
+ if (isAtBottom()) {
953
+ scrollToBottomBtn.classList.remove('show');
954
+ } else {
955
+ scrollToBottomBtn.classList.add('show');
956
+ }
957
+ } else {
958
+ // 如果内容未显示,确保按钮有 show 类(当内容显示时会自动显示)
959
+ scrollToBottomBtn.classList.add('show');
960
+ }
961
+ }
962
+
963
+ // 初始化函数
494
964
  function initScrollToBottom() {
495
- var scrollToBottomBtn = document.getElementById('scroll-to-bottom');
965
+ if (isInitialized) {
966
+ // 如果已初始化,只更新按钮状态
967
+ toggleButton();
968
+ // 即使已初始化,也确保点击事件已绑定
969
+ if (scrollToBottomBtn) {
970
+ scrollToBottomBtn.onclick = function(e) {
971
+ if (e) {
972
+ e.preventDefault();
973
+ e.stopPropagation();
974
+ }
975
+ console.log('按钮被点击了!');
976
+ var markdownBody = document.querySelector('.markdown-body');
977
+ var warpper = document.querySelector('.warpper');
978
+ var container = markdownBody || warpper || document.documentElement;
979
+ if (container && container.scrollTo) {
980
+ container.scrollTop = container.scrollHeight;
981
+ }
982
+ window.scrollTo(0, document.documentElement.scrollHeight);
983
+ return false;
984
+ };
985
+ }
986
+ return;
987
+ }
988
+
989
+ scrollToBottomBtn = document.getElementById('scroll-to-bottom');
990
+ mainContainer = document.getElementById('main-container');
991
+
496
992
  if (!scrollToBottomBtn) {
497
993
  return;
498
994
  }
499
995
 
500
- // 确保按钮可见(如果内容已显示)
501
- var mainContainer = document.getElementById('main-container');
996
+ isInitialized = true;
997
+
998
+ // 立即添加 show 类,确保按钮显示
502
999
  if (mainContainer && mainContainer.style.display !== 'none') {
503
1000
  scrollToBottomBtn.style.display = 'flex';
1001
+ scrollToBottomBtn.classList.add('show');
504
1002
  }
505
1003
 
506
- // 检查是否在页面底部
507
- function isAtBottom() {
508
- var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
509
- var scrollHeight = document.documentElement.scrollHeight;
510
- var clientHeight = document.documentElement.clientHeight;
511
- // 允许5px的误差
512
- return scrollHeight - scrollTop - clientHeight <= 5;
1004
+ // 滚动到底部 - 找到正确的滚动容器
1005
+ function scrollToBottom() {
1006
+ // 尝试找到滚动容器
1007
+ var markdownBody = document.querySelector('.markdown-body');
1008
+ var warpper = document.querySelector('.warpper');
1009
+ var container = markdownBody || warpper || document.documentElement;
1010
+
1011
+ // 滚动容器
1012
+ if (container) {
1013
+ container.scrollTop = container.scrollHeight;
1014
+ }
1015
+ // 同时滚动 window(以防万一)
1016
+ window.scrollTo(0, document.documentElement.scrollHeight);
513
1017
  }
514
1018
 
515
- // 显示/隐藏按钮
516
- function toggleButton() {
517
- // 确保按钮可见
518
- if (mainContainer && mainContainer.style.display !== 'none') {
519
- scrollToBottomBtn.style.display = 'flex';
1019
+ // 绑定点击事件 - 使用多种方式确保事件能触发
1020
+ var clickHandler = function(e) {
1021
+ if (e) {
1022
+ e.preventDefault();
1023
+ e.stopPropagation();
520
1024
  }
1025
+ // 找到滚动容器并滚动
1026
+ var markdownBody = document.querySelector('.markdown-body');
1027
+ var warpper = document.querySelector('.warpper');
1028
+ var container = markdownBody || warpper || document.documentElement;
521
1029
 
522
- if (isAtBottom()) {
523
- scrollToBottomBtn.classList.remove('show');
524
- } else {
525
- scrollToBottomBtn.classList.add('show');
1030
+ if (container) {
1031
+ container.scrollTop = container.scrollHeight;
526
1032
  }
527
- }
528
-
529
- // 滚动到底部
530
- function scrollToBottom() {
531
- window.scrollTo({
532
- top: document.documentElement.scrollHeight,
533
- behavior: 'smooth'
534
- });
535
- }
536
-
537
- // 绑定点击事件
538
- scrollToBottomBtn.addEventListener('click', function(e) {
539
- e.preventDefault();
540
- scrollToBottom();
541
- });
1033
+ // 同时滚动 window
1034
+ window.scrollTo(0, document.documentElement.scrollHeight);
1035
+ return false;
1036
+ };
1037
+ // 先移除可能存在的旧监听器
1038
+ scrollToBottomBtn.removeEventListener('click', clickHandler);
1039
+ // 添加新的监听器 - 使用捕获阶段
1040
+ scrollToBottomBtn.addEventListener('click', clickHandler, true);
1041
+ // 同时使用 onclick 属性作为备用
1042
+ scrollToBottomBtn.onclick = clickHandler;
542
1043
 
543
1044
  // 监听滚动事件
544
1045
  var scrollTimer = null;
@@ -550,8 +1051,17 @@ style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background:
550
1051
  scrollTimer = setTimeout(toggleButton, 100);
551
1052
  }, { passive: true });
552
1053
 
553
- // 初始检查
1054
+ // 初始检查(多次检查,确保页面渲染完成)
1055
+ // 直接添加 show 类,确保按钮显示
1056
+ if (mainContainer && mainContainer.style.display !== 'none') {
1057
+ scrollToBottomBtn.style.display = 'flex';
1058
+ scrollToBottomBtn.classList.add('show');
1059
+ }
1060
+ toggleButton();
1061
+ setTimeout(toggleButton, 100);
554
1062
  setTimeout(toggleButton, 300);
1063
+ setTimeout(toggleButton, 500);
1064
+ setTimeout(toggleButton, 1000);
555
1065
 
556
1066
  // 监听内容变化(处理动态加载的内容)
557
1067
  var observer = new MutationObserver(function() {
@@ -577,6 +1087,65 @@ style="position: fixed; top: 0; left: 0; width: 100%; height: 100%; background:
577
1087
  // 延迟初始化(处理动态显示的情况)
578
1088
  setTimeout(initScrollToBottom, 500);
579
1089
  setTimeout(initScrollToBottom, 1000);
1090
+ setTimeout(initScrollToBottom, 2000);
1091
+
1092
+ // 强制添加 show 类 - 不依赖任何条件
1093
+ function forceShowButton() {
1094
+ var btn = document.getElementById('scroll-to-bottom');
1095
+ var container = document.getElementById('main-container');
1096
+ if (btn && container && container.style.display !== 'none') {
1097
+ btn.style.display = 'flex';
1098
+ btn.classList.add('show');
1099
+ // 确保点击事件已绑定
1100
+ if (!btn.hasAttribute('data-click-bound')) {
1101
+ btn.addEventListener('click', function(e) {
1102
+ e.preventDefault();
1103
+ e.stopPropagation();
1104
+ var markdownBody = document.querySelector('.markdown-body');
1105
+ var warpper = document.querySelector('.warpper');
1106
+ var container = markdownBody || warpper || document.documentElement;
1107
+ if (container && container.scrollTo) {
1108
+ container.scrollTop = container.scrollHeight;
1109
+ }
1110
+ window.scrollTo(0, document.documentElement.scrollHeight);
1111
+ });
1112
+ btn.setAttribute('data-click-bound', 'true');
1113
+ }
1114
+ }
1115
+ }
1116
+
1117
+ // 在多个时机强制添加 show 类
1118
+ forceShowButton();
1119
+ setTimeout(forceShowButton, 100);
1120
+ setTimeout(forceShowButton, 200);
1121
+ setTimeout(forceShowButton, 500);
1122
+ setTimeout(forceShowButton, 1000);
1123
+ setTimeout(forceShowButton, 2000);
1124
+
1125
+ // 监听内容显示事件
1126
+ if (document.readyState === 'loading') {
1127
+ document.addEventListener('DOMContentLoaded', forceShowButton);
1128
+ }
1129
+
1130
+ // 使用 MutationObserver 监听 main-container 的显示状态
1131
+ var containerObserver = new MutationObserver(function(mutations) {
1132
+ mutations.forEach(function(mutation) {
1133
+ if (mutation.type === 'attributes' && mutation.attributeName === 'style') {
1134
+ var container = document.getElementById('main-container');
1135
+ if (container && container.style.display !== 'none') {
1136
+ forceShowButton();
1137
+ }
1138
+ }
1139
+ });
1140
+ });
1141
+
1142
+ var mainContainer = document.getElementById('main-container');
1143
+ if (mainContainer) {
1144
+ containerObserver.observe(mainContainer, {
1145
+ attributes: true,
1146
+ attributeFilter: ['style']
1147
+ });
1148
+ }
580
1149
  })();
581
1150
  </script>
582
1151
  <% include footer.ejs %>