修复AJAX 引擎

This commit is contained in:
2026-08-23 17:07:55 +08:00
parent 42288bb0b1
commit 8d2b78a322
5 changed files with 67 additions and 8 deletions
@@ -0,0 +1,48 @@
# 修复前台文章卡片无刷新加载出现空位的问题
## 根因
规范分页控件(`aksrt_render_pagination()` 输出的 `.ajax-pag[data-aksrt-pagination]`,内含 `.next-page.ajax-next`)携带了遗留引擎的触发类 `ajax-next`。全站加载的 `main.min.js` 在 body 上委托监听 `.ajax-next` 点击(另有 IAS 无限滚动路径用 jQuery 模拟点击 `.ajax-next/.ias-btn`),导致每次"加载更多"被两套引擎同时处理:
1. **规范引擎**(pagination.js):POST `aksrt_load_more_posts`,把卡片正确插入 `.ajax-pag` 之前;
2. **遗留引擎**(main.min.js `post_ajax()`):抓取整页 `?paged=2` HTML,**先删除 `.ajax-pag`**,把占位加载器、重复的一批卡片和一个新的**块级** `.ajax-pag` div 插到最后一张卡之后。
卡片网格是 inline-block 布局(`width: calc(33.333% - 16px)`),块级分页 div / 重复批次插入流中会强制换行 → 网格中出现空位(即"隔出一个卡片位置"),且第 2 页内容被加载两次。评论分页(`inc/helpers/template-tags/search-meta.php:533`)已用 `order-ajax-next` + `ias-btn` 避开遗留引擎,文章分页是唯一例外。
另经确认:生产环境实际生效的懒加载运行时是 main.min.js 内置版(`assets/js/lazysizes.js` 无任何 enqueue),其 IAS 自动加载走 jQuery 模拟点击,只到得了遗留引擎——所以无限滚动模式目前完全由遗留引擎执行。若只摘掉 `ajax-next` 类而不接管 IAS 触发,无限滚动会失效,因此两处改动必须配套。
## 修改内容(4 个文件)
### 1. `inc/helpers/template-tags/pagination-permissions.php:123`
`.next-page` 包装类的 `ajax-next` → `order-ajax-next ias-btn`:
- 移除遗留引擎的点击触发 token(手动点击与 IAS 模拟点击双双失效于遗留引擎);
- `order-ajax-next` 复用现有按钮样式 `.theme-pagination .order-ajax-next a`(main.css:9659+),**零 CSS 改动**;
- `ias-btn` 保持 main.min.js 的 IAS 匹配器仍能找到元素(其后续 jQuery 点击成为无害空操作),且 pagination.js 的 clickTarget 选择器 `.next-page.ajax-next, .ias-btn` 原生支持,**零 JS 选择器改动**;
- 与评论分页的既有模式完全一致。
### 2. `assets/js/core/pagination.js`
在点击绑定块后新增容器级 `lazybeforeunveil` 监听(仅当服务端输出了 `lazyload` 契约类时挂载):unveil 事件由 main.min.js 内置 lazySizes 原生派发(可冒泡),监听到后设置 `lazyAuto` 并原生 `click()`,把无限滚动自动加载**收归规范引擎**的既有点击管线(复用 loading 守卫、iasMax 上限、按钮状态机):
```js
if (container.classList.contains("lazyload") || clickTarget.classList.contains("lazyload")) {
container.addEventListener("lazybeforeunveil", function (e) {
if (e.target !== container && e.target !== clickTarget) return;
clickTarget.dataset.lazyAuto = "1";
clickTarget.click();
});
}
```
附带修复:评论分页的 IAS 自动加载此前同样到不了规范引擎(jQuery 模拟点击不可见),此监听一并接管。
### 3. `search.php:112-118` — 消除双层包裹
去掉外层冗余 `<div class="posts-row mtn6">`,把 `mtn6` 直接传入 `aksrt_render_post_list(['wrapper_class' => 'mtn6'])`。这样规范引擎的 `previousElementSibling` 目标解析落在真正的卡片网格上,追加的卡片与首页批在同一 inline-block 网格内连续排布(此前新卡片会追加为内层网格块的兄弟节点,卡片模式下在分页边界处出现空位)。ajax-list.js(搜索 tab 切换的实际引擎)用 `querySelectorAll('.ajax-item')` 提取、其替换流程本身就会把卡片拍平到容器层,结构兼容。
### 4. `tests/widget-system/post-visual-contract.test.cjs:238`
- 断言 `/class="next-page ajax-next/` → `/class="next-page order-ajax-next ias-btn/`;
- 新增 `assert.doesNotMatch(php, /next-page ajax-next/)` 锁定规范控件不再携带遗留触发类;
- 新增 `assert.match(js, /lazybeforeunveil/)` 锁定 IAS 接管。
## 验证
- `php -l inc/helpers/template-tags/pagination-permissions.php` 和 `php -l search.php`
- `node --test tests/widget-system/post-visual-contract.test.cjs`
- 浏览器实测(桌面 3 列卡片网格):首页点"加载更多"只发一个 `admin-ajax` 请求、无重复批次、无网格空位、`.ajax-pag` 始终位于网格下方;无限滚动模式每次自动加载一页并在 iasMax 后转手动按钮;搜索页卡片模式追加后与首批网格连续。
+11
View File
@@ -256,6 +256,17 @@
});
}
// The runtime lazySizes dispatches lazybeforeunveil natively but follows up
// with a jQuery-simulated click, which native listeners never receive.
// Route the unveil trigger through the same click pipeline.
if (container.classList.contains("lazyload") || clickTarget.classList.contains("lazyload")) {
container.addEventListener("lazybeforeunveil", function (e) {
if (e.target !== container && e.target !== clickTarget) return;
clickTarget.dataset.lazyAuto = "1";
clickTarget.click();
});
}
if (mode === "infinite") {
if ((isComment && window.aksrtData && aksrtData.commentIasAuto === false) || !hasAjaxConfig()) {
var autoTrigger = clickTarget.closest(".next-page") || clickTarget;
@@ -120,7 +120,7 @@ if (!function_exists('aksrt_render_pagination')) {
data-query-context="<?php echo esc_attr($query_context); ?>"
data-query-vars="<?php echo esc_attr(wp_json_encode($query_vars)); ?>"
data-render-config="<?php echo esc_attr(wp_json_encode($render_config)); ?>">
<div class="next-page ajax-next<?php echo $auto_load ? ' lazyload' : ''; ?>"<?php echo $auto_load ? ' lazyload-action="ias"' : ''; ?>>
<div class="next-page order-ajax-next ias-btn<?php echo $auto_load ? ' lazyload' : ''; ?>"<?php echo $auto_load ? ' lazyload-action="ias"' : ''; ?>>
<a href="<?php echo esc_url(add_query_arg($page_var, $current_page + 1)); ?>" data-aksrt-load-more><?php echo wp_kses_post($trigger_text); ?></a>
</div>
<div class="post_ajax_loader" style="display:none;" aria-hidden="true"><?php echo function_exists('aksrt_render_placeholder') ? aksrt_render_placeholder('list', 2) : ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></div>
+1 -3
View File
@@ -110,12 +110,10 @@ if (is_active_sidebar('search_top_fluid')) {
}
?>
<?php elseif ($search_type === 'post' && $wp_query->have_posts()) : ?>
<div class="posts-row mtn6">
<?php
$config = function_exists('aksrt_archive_get_render_config') ? aksrt_archive_get_render_config(['context' => 'search', 'highlight_query' => $search_query]) : ['context' => 'search', 'mode' => 'list'];
aksrt_render_post_list(array_merge($config, ['wrapper_class' => '']), $wp_query);
aksrt_render_post_list(array_merge($config, ['wrapper_class' => 'mtn6']), $wp_query);
?>
</div>
<?php aksrt_render_pagination($wp_query, ['query_context' => 'search', 'render_config' => $config]); ?>
<?php else : ?>
<div class="aksrt-panel search-content"><div class="text-center muted-2-color padding-20"><?php esc_html_e('未找到相关内容', 'aksrt'); ?></div></div>
@@ -235,8 +235,10 @@ test('AJAX pagination can recover, caps auto loading and rehydrates appended med
const media = read('assets/js/core/misc.js');
assert.match(php, /class="text-center theme-pagination ajax-pag"/);
assert.match(php, /class="next-page ajax-next/);
assert.match(php, /class="next-page order-ajax-next ias-btn/);
assert.doesNotMatch(php, /next-page ajax-next/);
assert.match(php, /lazyload-action="ias"/);
assert.match(js, /lazybeforeunveil/);
assert.match(php, /class="post_ajax_loader"/);
assert.match(php, /data-page-var/);
assert.match(admin, /'author', 'author_name'/);