diff --git a/assets/js/build/public.js b/assets/js/build/public.js index 782317cc..02b1a939 100644 --- a/assets/js/build/public.js +++ b/assets/js/build/public.js @@ -2659,13 +2659,93 @@ tbquire.config({ } function getCurrentAuthorOnly() { - var url = new URL(window.location.href); - if (url.searchParams.get("aksrt_author_only") === "1") return true; var btn = document.querySelector("#comments .btn-only-author"); return !!(btn && btn.classList.contains("active") && btn.dataset.authorOnly === "0"); } - function applyFragmentPayload(commentsArea, data, urlState) { + /* ====== 全局无参数加载:评论状态仅保存在客户端,地址栏不携带 ? 参数 ====== */ + var COMMENT_URL_PARAMS = ["cpage", "aksrt_comment_order", "aksrt_author_only"]; + var commentUrlStateCleaned = false; + + function stripCommentUrlParams() { + if (commentUrlStateCleaned || !window.history || typeof window.history.replaceState !== "function") return; + commentUrlStateCleaned = true; + var url = new URL(window.location.href); + var changed = false; + COMMENT_URL_PARAMS.forEach(function (key) { + if (url.searchParams.has(key)) { + url.searchParams.delete(key); + changed = true; + } + }); + if (changed) { + // 服务端首屏已按参数渲染完毕,落地后地址栏回到无参干净链接。 + window.history.replaceState(null, "", url.toString()); + } + } + + function getMaxCommentPages() { + var pagenav = document.querySelector("#comments .pagenav[data-max-pages]"); + if (pagenav) { + var max = parseInt(pagenav.dataset.maxPages, 10); + if (max > 0) return max; + } + var jumpInput = document.querySelector("#comments .jump-input[max]"); + if (jumpInput) { + var maxAttr = parseInt(jumpInput.getAttribute("max"), 10); + if (maxAttr > 0) return maxAttr; + } + return 1; + } + + function parseCommentPageFromHref(href) { + if (!href || href === "#" || href.indexOf("javascript:") === 0) return 0; + try { + var url = new URL(href, window.location.href); + var cpage = parseInt(url.searchParams.get("cpage"), 10); + if (cpage > 0) return cpage; + var match = url.pathname.match(/\/comment-page-([0-9]{1,})\/?$/); + return match ? parseInt(match[1], 10) : 0; + } catch (e) { + return 0; + } + } + + function scrollCommentsIntoView() { + var commentsArea = document.getElementById("comments"); + if (!commentsArea || typeof commentsArea.scrollIntoView !== "function") return; + var rect = commentsArea.getBoundingClientRect(); + if (rect.top >= 0 && rect.top < window.innerHeight * 0.6) return; + commentsArea.scrollIntoView({ behavior: "smooth", block: "start" }); + } + + function loadCommentPage(page, opts) { + opts = opts || {}; + var commentsArea = document.getElementById("comments"); + if (!commentsArea) { + return Promise.reject(new Error("comments area missing")); + } + var maxPages = getMaxCommentPages(); + page = parseInt(page, 10) || 1; + page = Math.max(1, page); + if (maxPages > 1) page = Math.min(page, maxPages); + + showListLoading(commentsArea); + return fetchCommentFragment({ + order: getCurrentCommentOrder(), + authorOnly: getCurrentAuthorOnly(), + page: page + }).then(function (json) { + if (json && json.success && json.data) { + applyFragmentPayload(commentsArea, json.data); + if (!opts.noScroll) scrollCommentsIntoView(); + return true; + } + throw new Error("comment fragment failed"); + }); + } + + function applyFragmentPayload(commentsArea, data) { if (!commentsArea || !data || !data.html) return; // data.html 是完整的
(含筛选、列表、分页) @@ -2684,9 +2764,6 @@ tbquire.config({ var currentCount = commentsArea.querySelector(".title-theme small"); if (currentCount && data.count_text) currentCount.textContent = data.count_text; - if (urlState && window.history && typeof window.history.replaceState === "function") { - window.history.replaceState(null, "", urlState); - } if (window.AksrtFrontend) AksrtFrontend.rehydrate(commentsArea, "ajax"); } @@ -2731,24 +2808,7 @@ tbquire.config({ } function reloadCommentList() { - var commentsArea = document.getElementById('comments'); - if (!commentsArea) { - window.location.reload(); - return; - } - showListLoading(commentsArea); - - fetchCommentFragment({ - order: getCurrentCommentOrder(), - authorOnly: getCurrentAuthorOnly(), - page: 1 - }).then(function (json) { - if (json && json.success && json.data) { - applyFragmentPayload(commentsArea, json.data, null); - return; - } - throw new Error('fragment failed'); - }).catch(function (error) { + loadCommentPage(1, { noScroll: true }).catch(function (error) { console.error('[AKSRT Comment] 刷新评论列表失败:', error); window.location.reload(); }); @@ -2791,23 +2851,19 @@ tbquire.config({ } renderLoadingState(); var authorOnly = getCurrentAuthorOnly(); - var url = new URL(window.location.href); - url.searchParams.set("aksrt_comment_order", order); - url.searchParams.delete("cpage"); - if (authorOnly) url.searchParams.set("aksrt_author_only", "1"); - else url.searchParams.delete("aksrt_author_only"); fetchCommentFragment({ order: order, authorOnly: authorOnly, page: 1 }) .then(function (json) { if (json && json.success && json.data) { - applyFragmentPayload(commentsArea, json.data, url.toString()); + applyFragmentPayload(commentsArea, json.data); return; } throw new Error("order fragment failed"); }) .catch(function (error) { console.error("[AKSRT Comment] 排序刷新失败:", error); - window.location.href = url.toString(); + // 兜底整页刷新,地址栏保持无参。 + window.location.reload(); }); } @@ -2815,23 +2871,19 @@ tbquire.config({ renderLoadingState(); var authorOnly = authorOnlyFlag === "1" || authorOnlyFlag === 1 || authorOnlyFlag === true; var order = getCurrentCommentOrder(); - var url = new URL(window.location.href); - if (authorOnly) url.searchParams.set("aksrt_author_only", "1"); - else url.searchParams.delete("aksrt_author_only"); - url.searchParams.delete("cpage"); - if (order) url.searchParams.set("aksrt_comment_order", order); fetchCommentFragment({ order: order, authorOnly: authorOnly, page: 1 }) .then(function (json) { if (json && json.success && json.data) { - applyFragmentPayload(commentsArea, json.data, url.toString()); + applyFragmentPayload(commentsArea, json.data); return; } throw new Error("author fragment failed"); }) .catch(function (error) { console.error("[AKSRT Comment] Author filter failed:", error); - window.location.href = url.toString(); + // 兜底整页刷新,地址栏保持无参。 + window.location.reload(); }); } @@ -2851,6 +2903,21 @@ tbquire.config({ if (orderBtn && commentsArea.contains(orderBtn)) { e.preventDefault(); applyCommentOrder(orderBtn.getAttribute("data-order") || "newest"); + return; + } + + // 数字分页:本地 DOM 刷新,地址栏不携带参数(href 仅作无 JS 兜底)。 + var pageLink = target.closest(".pagenav a.page-numbers"); + if (pageLink && commentsArea.contains(pageLink) && !pageLink.classList.contains("pag-jump")) { + var page = parseCommentPageFromHref(pageLink.getAttribute("href")); + if (page > 0) { + e.preventDefault(); + loadCommentPage(page).catch(function (error) { + console.error("[AKSRT Comment] 分页刷新失败:", error); + // AJAX 不可用时退回原始链接(pretty 链接本身无 ? 参数)。 + window.location.href = pageLink.href; + }); + } } }); } @@ -2858,11 +2925,10 @@ tbquire.config({ /* ====== 数字分页跳页(legacy pag-jump) ====== */ function jumpToCommentPage(page) { - page = parseInt(page, 10) || 1; - var url = new URL(window.location.href); - url.searchParams.set("cpage", String(page)); - url.hash = "comments"; - window.location.href = url.toString(); + loadCommentPage(page).catch(function (error) { + console.error("[AKSRT Comment] 跳页失败:", error); + window.location.reload(); + }); } function initCommentPageJump() { @@ -2883,8 +2949,18 @@ tbquire.config({ }); } - window.AksrtFrontend.register("aksrt-comment-system", function () { initCommentSystem(); initCommentPageJump(); }); + window.AksrtFrontend.register("aksrt-comment-system", function () { + stripCommentUrlParams(); + initCommentSystem(); + initCommentPageJump(); + }); window.AksrtFrontend.register("aksrt-comment-order", function (root) { initCommentOrder(root); }); + + // 供 pagination.js 等模块复用:评论页码加载 / 列表刷新(局部 DOM,无 ? 参数)。 + window.AksrtComments = { + loadPage: function (page, opts) { return loadCommentPage(page, opts); }, + reload: function () { reloadCommentList(); } + }; })(); ; @@ -3827,9 +3903,14 @@ tbquire.config({ var targetPage = parseInt(jumpInput.value, 10) || 1; var max = parseInt(jumpInput.dataset.maxPages || String(maxPages), 10) || maxPages; targetPage = Math.max(1, Math.min(max, targetPage)); - var url = new URL(window.location.href); - url.searchParams.set("cpage", String(targetPage)); - window.location.href = url.toString(); + // 评论跳页:本地 DOM 刷新,地址栏不携带 ? 参数。 + if (window.AksrtComments && typeof window.AksrtComments.loadPage === "function") { + e.preventDefault(); + window.AksrtComments.loadPage(targetPage); + return; + } + window.location.hash = "comments"; + window.location.reload(); return; } if (loadMoreBtn.dataset.jumpArchive === "1") { diff --git a/assets/js/core/comments.js b/assets/js/core/comments.js index 9c62129d..5e09132e 100644 --- a/assets/js/core/comments.js +++ b/assets/js/core/comments.js @@ -476,13 +476,93 @@ } function getCurrentAuthorOnly() { - var url = new URL(window.location.href); - if (url.searchParams.get("aksrt_author_only") === "1") return true; var btn = document.querySelector("#comments .btn-only-author"); return !!(btn && btn.classList.contains("active") && btn.dataset.authorOnly === "0"); } - function applyFragmentPayload(commentsArea, data, urlState) { + /* ====== 全局无参数加载:评论状态仅保存在客户端,地址栏不携带 ? 参数 ====== */ + var COMMENT_URL_PARAMS = ["cpage", "aksrt_comment_order", "aksrt_author_only"]; + var commentUrlStateCleaned = false; + + function stripCommentUrlParams() { + if (commentUrlStateCleaned || !window.history || typeof window.history.replaceState !== "function") return; + commentUrlStateCleaned = true; + var url = new URL(window.location.href); + var changed = false; + COMMENT_URL_PARAMS.forEach(function (key) { + if (url.searchParams.has(key)) { + url.searchParams.delete(key); + changed = true; + } + }); + if (changed) { + // 服务端首屏已按参数渲染完毕,落地后地址栏回到无参干净链接。 + window.history.replaceState(null, "", url.toString()); + } + } + + function getMaxCommentPages() { + var pagenav = document.querySelector("#comments .pagenav[data-max-pages]"); + if (pagenav) { + var max = parseInt(pagenav.dataset.maxPages, 10); + if (max > 0) return max; + } + var jumpInput = document.querySelector("#comments .jump-input[max]"); + if (jumpInput) { + var maxAttr = parseInt(jumpInput.getAttribute("max"), 10); + if (maxAttr > 0) return maxAttr; + } + return 1; + } + + function parseCommentPageFromHref(href) { + if (!href || href === "#" || href.indexOf("javascript:") === 0) return 0; + try { + var url = new URL(href, window.location.href); + var cpage = parseInt(url.searchParams.get("cpage"), 10); + if (cpage > 0) return cpage; + var match = url.pathname.match(/\/comment-page-([0-9]{1,})\/?$/); + return match ? parseInt(match[1], 10) : 0; + } catch (e) { + return 0; + } + } + + function scrollCommentsIntoView() { + var commentsArea = document.getElementById("comments"); + if (!commentsArea || typeof commentsArea.scrollIntoView !== "function") return; + var rect = commentsArea.getBoundingClientRect(); + if (rect.top >= 0 && rect.top < window.innerHeight * 0.6) return; + commentsArea.scrollIntoView({ behavior: "smooth", block: "start" }); + } + + function loadCommentPage(page, opts) { + opts = opts || {}; + var commentsArea = document.getElementById("comments"); + if (!commentsArea) { + return Promise.reject(new Error("comments area missing")); + } + var maxPages = getMaxCommentPages(); + page = parseInt(page, 10) || 1; + page = Math.max(1, page); + if (maxPages > 1) page = Math.min(page, maxPages); + + showListLoading(commentsArea); + return fetchCommentFragment({ + order: getCurrentCommentOrder(), + authorOnly: getCurrentAuthorOnly(), + page: page + }).then(function (json) { + if (json && json.success && json.data) { + applyFragmentPayload(commentsArea, json.data); + if (!opts.noScroll) scrollCommentsIntoView(); + return true; + } + throw new Error("comment fragment failed"); + }); + } + + function applyFragmentPayload(commentsArea, data) { if (!commentsArea || !data || !data.html) return; // data.html 是完整的
(含筛选、列表、分页) @@ -501,9 +581,6 @@ var currentCount = commentsArea.querySelector(".title-theme small"); if (currentCount && data.count_text) currentCount.textContent = data.count_text; - if (urlState && window.history && typeof window.history.replaceState === "function") { - window.history.replaceState(null, "", urlState); - } if (window.AksrtFrontend) AksrtFrontend.rehydrate(commentsArea, "ajax"); } @@ -548,24 +625,7 @@ } function reloadCommentList() { - var commentsArea = document.getElementById('comments'); - if (!commentsArea) { - window.location.reload(); - return; - } - showListLoading(commentsArea); - - fetchCommentFragment({ - order: getCurrentCommentOrder(), - authorOnly: getCurrentAuthorOnly(), - page: 1 - }).then(function (json) { - if (json && json.success && json.data) { - applyFragmentPayload(commentsArea, json.data, null); - return; - } - throw new Error('fragment failed'); - }).catch(function (error) { + loadCommentPage(1, { noScroll: true }).catch(function (error) { console.error('[AKSRT Comment] 刷新评论列表失败:', error); window.location.reload(); }); @@ -608,23 +668,19 @@ } renderLoadingState(); var authorOnly = getCurrentAuthorOnly(); - var url = new URL(window.location.href); - url.searchParams.set("aksrt_comment_order", order); - url.searchParams.delete("cpage"); - if (authorOnly) url.searchParams.set("aksrt_author_only", "1"); - else url.searchParams.delete("aksrt_author_only"); fetchCommentFragment({ order: order, authorOnly: authorOnly, page: 1 }) .then(function (json) { if (json && json.success && json.data) { - applyFragmentPayload(commentsArea, json.data, url.toString()); + applyFragmentPayload(commentsArea, json.data); return; } throw new Error("order fragment failed"); }) .catch(function (error) { console.error("[AKSRT Comment] 排序刷新失败:", error); - window.location.href = url.toString(); + // 兜底整页刷新,地址栏保持无参。 + window.location.reload(); }); } @@ -632,23 +688,19 @@ renderLoadingState(); var authorOnly = authorOnlyFlag === "1" || authorOnlyFlag === 1 || authorOnlyFlag === true; var order = getCurrentCommentOrder(); - var url = new URL(window.location.href); - if (authorOnly) url.searchParams.set("aksrt_author_only", "1"); - else url.searchParams.delete("aksrt_author_only"); - url.searchParams.delete("cpage"); - if (order) url.searchParams.set("aksrt_comment_order", order); fetchCommentFragment({ order: order, authorOnly: authorOnly, page: 1 }) .then(function (json) { if (json && json.success && json.data) { - applyFragmentPayload(commentsArea, json.data, url.toString()); + applyFragmentPayload(commentsArea, json.data); return; } throw new Error("author fragment failed"); }) .catch(function (error) { console.error("[AKSRT Comment] Author filter failed:", error); - window.location.href = url.toString(); + // 兜底整页刷新,地址栏保持无参。 + window.location.reload(); }); } @@ -668,6 +720,21 @@ if (orderBtn && commentsArea.contains(orderBtn)) { e.preventDefault(); applyCommentOrder(orderBtn.getAttribute("data-order") || "newest"); + return; + } + + // 数字分页:本地 DOM 刷新,地址栏不携带参数(href 仅作无 JS 兜底)。 + var pageLink = target.closest(".pagenav a.page-numbers"); + if (pageLink && commentsArea.contains(pageLink) && !pageLink.classList.contains("pag-jump")) { + var page = parseCommentPageFromHref(pageLink.getAttribute("href")); + if (page > 0) { + e.preventDefault(); + loadCommentPage(page).catch(function (error) { + console.error("[AKSRT Comment] 分页刷新失败:", error); + // AJAX 不可用时退回原始链接(pretty 链接本身无 ? 参数)。 + window.location.href = pageLink.href; + }); + } } }); } @@ -675,11 +742,10 @@ /* ====== 数字分页跳页(legacy pag-jump) ====== */ function jumpToCommentPage(page) { - page = parseInt(page, 10) || 1; - var url = new URL(window.location.href); - url.searchParams.set("cpage", String(page)); - url.hash = "comments"; - window.location.href = url.toString(); + loadCommentPage(page).catch(function (error) { + console.error("[AKSRT Comment] 跳页失败:", error); + window.location.reload(); + }); } function initCommentPageJump() { @@ -700,6 +766,16 @@ }); } - window.AksrtFrontend.register("aksrt-comment-system", function () { initCommentSystem(); initCommentPageJump(); }); + window.AksrtFrontend.register("aksrt-comment-system", function () { + stripCommentUrlParams(); + initCommentSystem(); + initCommentPageJump(); + }); window.AksrtFrontend.register("aksrt-comment-order", function (root) { initCommentOrder(root); }); + + // 供 pagination.js 等模块复用:评论页码加载 / 列表刷新(局部 DOM,无 ? 参数)。 + window.AksrtComments = { + loadPage: function (page, opts) { return loadCommentPage(page, opts); }, + reload: function () { reloadCommentList(); } + }; })(); diff --git a/assets/js/core/pagination.js b/assets/js/core/pagination.js index 2aa9f9a2..d8c476a8 100644 --- a/assets/js/core/pagination.js +++ b/assets/js/core/pagination.js @@ -228,9 +228,14 @@ var targetPage = parseInt(jumpInput.value, 10) || 1; var max = parseInt(jumpInput.dataset.maxPages || String(maxPages), 10) || maxPages; targetPage = Math.max(1, Math.min(max, targetPage)); - var url = new URL(window.location.href); - url.searchParams.set("cpage", String(targetPage)); - window.location.href = url.toString(); + // 评论跳页:本地 DOM 刷新,地址栏不携带 ? 参数。 + if (window.AksrtComments && typeof window.AksrtComments.loadPage === "function") { + e.preventDefault(); + window.AksrtComments.loadPage(targetPage); + return; + } + window.location.hash = "comments"; + window.location.reload(); return; } if (loadMoreBtn.dataset.jumpArchive === "1") { diff --git a/inc/helpers/aksrt-comments.php b/inc/helpers/aksrt-comments.php index 5ae70955..1176d10d 100644 --- a/inc/helpers/aksrt-comments.php +++ b/inc/helpers/aksrt-comments.php @@ -653,7 +653,7 @@ if (!function_exists('aksrt_comments_render')) : ? sprintf(__('共%s条', 'aksrt'), (string) $count) : __('抢沙发', 'aksrt'); ?> -
+
' . esc_html($count_label) . ''; ?> diff --git a/inc/helpers/template-tags/search-meta.php b/inc/helpers/template-tags/search-meta.php index b3f3c996..cc091115 100644 --- a/inc/helpers/template-tags/search-meta.php +++ b/inc/helpers/template-tags/search-meta.php @@ -575,9 +575,17 @@ if (!function_exists('aksrt_render_comment_pagination')) { } // 数字分页(legacy:paginate_links + 跳页输入框) + // 路径式 comment-page-N 链接:地址栏与 href 均不携带 ? 参数(无 JS 时仍可整页翻页)。 + global $wp_rewrite; + if (get_option('permalink_structure') && $wp_rewrite instanceof WP_Rewrite && !empty($wp_rewrite->comments_pagination_base)) { + $base = user_trailingslashit(trailingslashit(get_permalink()) . $wp_rewrite->comments_pagination_base . '-%#%', 'commentpaged'); + } else { + // 无伪静态时只能用查询参数(页面地址本身已带 ?p=)。 + $base = add_query_arg('cpage', '%#%', get_permalink()); + } $is_mobile = wp_is_mobile(); $args = [ - 'base' => add_query_arg('cpage', '%#%', get_permalink()), + 'base' => $base, 'type' => 'array', 'mid_size' => $is_mobile ? 1 : 2, 'prev_text' => '' . __('上一页', 'aksrt') . '', @@ -596,7 +604,7 @@ if (!function_exists('aksrt_render_comment_pagination')) { $array[] = '' . __('跳转', 'aksrt') . ''; } - echo '