Mayx's Home Page
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

152 lines
5.7 KiB

  1. /**
  2. * PJAX 初始化与页面切换重绑定脚本
  3. * 依赖jQuery, jquery.pjax.min.js
  4. * 加载顺序 jquery.pjax.min.js 之后body 末尾
  5. */
  6. (function ($) {
  7. // ========== 常量 ==========
  8. var CONTAINER = '#pjax-container';
  9. var PJAX_OPTS = {
  10. container: CONTAINER,
  11. fragment: CONTAINER,
  12. timeout: 5000,
  13. scrollTo: false
  14. };
  15. // ========== 各组件重初始化 ==========
  16. /** Google Analytics 页面浏览事件 */
  17. function trackPageView() {
  18. if (typeof gtag === 'function') {
  19. gtag('config', window._gaId || '', { page_path: window.location.pathname });
  20. }
  21. }
  22. /** Live2D 重初始化 */
  23. var _live2dSelectors = ['.post-link', '#search-input'];
  24. var _live2dDelegateBound = false;
  25. function reinitLive2d() {
  26. if (!window._live2d) return;
  27. var pathname = window.location.pathname;
  28. // 更新"想问这篇文章"相关状态(仅真正的文章页显示)
  29. $('#post_id').val(pathname);
  30. if ($(CONTAINER + ' #gitalk-container').length > 0) {
  31. $('.live_talk_input_name_body').show();
  32. } else {
  33. $('.live_talk_input_name_body').hide();
  34. $('#load_this').prop('checked', false);
  35. }
  36. // 音乐按钮:根据当前页面是否有 BGM 输入来显示/隐藏
  37. if (typeof window._live2d.initBGM === 'function') {
  38. window._live2d.initBGM();
  39. }
  40. // 事件委托绑定(只执行一次)
  41. if (!_live2dDelegateBound && typeof String.prototype.renderTip === 'function') {
  42. var selector = CONTAINER + ' ' + _live2dSelectors.join(', ' + CONTAINER + ' ');
  43. $(document).on('mouseover._live2d_pjax', selector, function (e) {
  44. var $el = $(e.currentTarget || e.target);
  45. if ($el.is('.post-link')) {
  46. window._live2d.showMessage('要看看 ' + $el.text() + ' 么?', 3000);
  47. } else if ($el.is('#search-input')) {
  48. window._live2d.showMessage('在找什么东西呢,需要帮忙吗?', 3000);
  49. }
  50. });
  51. $(document).on('mouseout._live2d_pjax', selector, function () {
  52. if (window._live2d.showHitokoto) window._live2d.showHitokoto();
  53. });
  54. _live2dDelegateBound = true;
  55. }
  56. // 欢迎语
  57. if (typeof window._live2d.showMessage === 'function') {
  58. window._live2d.showMessage(getWelcomeText(pathname), 6000);
  59. }
  60. }
  61. // ========== PJAX 导航 ==========
  62. /** PJAX 完成后的统一处理 */
  63. function doPjaxComplete() {
  64. $('body').removeClass('pjax-loading');
  65. // 清理可能残留的浮层(如推荐文章 tooltip,hover 后点击跳转时 mouseleave 来不及触发)
  66. $('.content-tooltip').remove();
  67. onPjaxComplete();
  68. }
  69. /** 暴露给模板内 onclick/onchange 调用的导航函数 */
  70. window.go = function (url) {
  71. $.pjax($.extend({ url: url }, PJAX_OPTS));
  72. };
  73. // ========== 初始化 ==========
  74. /** pjax 完成后滚动到目标位置:有锚点则定位锚点,否则回到顶部 */
  75. function scrollToAnchor() {
  76. var hash = window.location.hash;
  77. if (hash) {
  78. // 中文等非 ASCII 字符在 URL 中会被编码,需先解码再匹配元素 id
  79. var id = hash.slice(1);
  80. try { id = decodeURIComponent(id); } catch (e) { /* 保持原值 */ }
  81. var target = document.getElementById(id) ||
  82. document.querySelector('a[name="' + id + '"]');
  83. if (target) {
  84. target.scrollIntoView({ behavior: 'smooth', block: 'start' });
  85. return;
  86. }
  87. }
  88. window.scrollTo(0, 0);
  89. }
  90. /** 每次 pjax 完成后执行所有重初始化 */
  91. function onPjaxComplete() {
  92. initVisitors();
  93. initCopyButtons();
  94. highlightKeyword();
  95. reinitLive2d();
  96. trackPageView();
  97. scrollToAnchor();
  98. }
  99. $(document).ready(function () {
  100. // 排除列表:外链、锚点、静态资源、Live2D 目录
  101. var exclude = ':not([target="_blank"]):not([href^="http"]):not([href^="//"])' +
  102. ':not([href^="mailto"]):not([href^="#"])' +
  103. ':not([href$=".xml"]):not([href$=".json"]):not([href$=".tgz"]):not([href$=".zip"])' +
  104. ':not([href^="/Live2dHistoire"])';
  105. $(document).pjax('a' + exclude, PJAX_OPTS.container, PJAX_OPTS);
  106. $(document).on('submit', 'form#search-input-all', function (e) {
  107. $.pjax.submit(e, PJAX_OPTS.container, PJAX_OPTS);
  108. });
  109. $(document).on('pjax:send', function () {
  110. $('body').addClass('pjax-loading');
  111. });
  112. $(document).on('pjax:complete', doPjaxComplete);
  113. $(document).on('pjax:end', function (event, xhr, options) {
  114. var $container = $(options.container || PJAX_OPTS.container);
  115. $container.find('script[type="module"]').each(function () {
  116. var oldScript = this;
  117. var newScript = document.createElement('script');
  118. newScript.type = 'module';
  119. // 如果是外链脚本 (<script src="..."></script>)
  120. if (oldScript.src) {
  121. newScript.src = oldScript.src;
  122. } else {
  123. // 如果是行内脚本 (<script>...code...</script>)
  124. newScript.textContent = oldScript.textContent;
  125. }
  126. // 插入到 body 中触发浏览器执行
  127. document.body.appendChild(newScript);
  128. // 运行完后建议移除,防止 DOM 变得混乱(不影响模块执行)
  129. newScript.remove();
  130. });
  131. });
  132. });
  133. })(jQuery);