fix(homepage): unify runtime rendering contract

This commit is contained in:
kate522 committed 2026-07-28 02:54:18 +08:00
1 parent bd6f55c42e
commit bcebd37807
13 files changed
+951 -926

No files matched your search

+8 -3
View File
@@ -34,8 +34,9 @@
var observer = null;
var iasEnabled = false;
var successfulAutoLoads = 0;
var target = container.previousElementSibling;
if (target && target.classList && target.classList.contains("content-stream__footer")) {
var homepagePanel = container.closest("[data-home-tab-panel]");
var target = homepagePanel || container.previousElementSibling;
if (!homepagePanel && target && target.classList && target.classList.contains("content-stream__footer")) {
target = target.previousElementSibling;
}
if (isComment) {
@@ -161,7 +162,11 @@
temp.innerHTML = res.data.html;
var newItems = temp.children;
while (newItems.length > 0) {
target.appendChild(newItems[0]);
if (homepagePanel && container.parentNode === target) {
target.insertBefore(newItems[0], container);
} else {
target.appendChild(newItems[0]);
}
}
if (isComment && window.AksrtFrontend) {
AksrtFrontend.rehydrate(target, "ajax");
+93 -26
View File
@@ -278,10 +278,12 @@
* Sets data-view, re-binds lazy images, and dispatches events.
*/
function notifyPostsRendered(panel, viewMode) {
var postsContainer = panel.querySelector('.aksrt-homepage__posts, .posts-row');
if (postsContainer) {
postsContainer.setAttribute('data-view', viewMode || getDefaultView());
}
var postsContainer = panel.matches('.aksrt-homepage__posts, .posts-row')
? panel
: panel.querySelector('.aksrt-homepage__posts, .posts-row');
if (postsContainer) {
postsContainer.setAttribute('data-view', viewMode || getDefaultView());
}
hydrateLazyImages(panel);
dispatchRenderedEvent(panel, {
@@ -294,6 +296,37 @@
* Unified AJAX panel loader
* ============================================================ */
function renderPanelPager(panel, options, hasMore) {
var existing = panel.querySelector('.aksrt-homepage__panel-footer');
if (existing) existing.remove();
if (!hasMore) return;
var footer = document.createElement('div');
footer.className = 'aksrt-homepage__panel-footer';
var button = document.createElement('button');
button.type = 'button';
button.className = 'aksrt-homepage__more';
button.textContent = (window.aksrtData && aksrtData.ajaxTrigger) || '加载更多';
button.addEventListener('click', function () {
button.disabled = true;
button.textContent = (window.aksrtData && aksrtData.ajaxLoading) || '正在加载...';
requestHomepagePanel(panel, {
termId: options.termId,
page: options.page + 1,
perPage: options.perPage,
sort: options.sort,
viewMode: options.viewMode,
pageUrl: options.pageUrl,
panel: options.panel,
source: options.source,
tabOrderby: options.tabOrderby,
append: true
});
});
footer.appendChild(button);
panel.appendChild(footer);
}
function buildErrorState(panel, requestOptions) {
var wrapper = document.createElement('div');
wrapper.className = 'aksrt-homepage__tab-error';
@@ -334,7 +367,8 @@
pageUrl: requestOptions.pageUrl || window.location.href,
panel: requestOptions.panel || panel.getAttribute('data-home-tab-panel') || 'latest',
source: requestOptions.source || getPanelSource(panel),
tabOrderby: requestOptions.tabOrderby || getPanelTabOrderby(panel) || ''
tabOrderby: requestOptions.tabOrderby || getPanelTabOrderby(panel) || '',
append: requestOptions.append === true
};
var restUrl = buildRestUrl(options);
@@ -352,14 +386,16 @@
url: restUrl
});
// Show loading skeleton
panel.innerHTML = '';
panel.appendChild(buildSkeleton(options.perPage > 6 ? 4 : 3));
// Full refreshes replace the panel; append requests keep existing cards.
if (!options.append) {
panel.innerHTML = '';
panel.appendChild(buildSkeleton(options.perPage > 6 ? 4 : 3));
}
function markLoaded() {
panel.dataset.loaded = 'true';
panel.dataset.loadedPage = String(options.page);
panel.dataset.loadedSort = options.sort;
panel.dataset.loadedSort = options.tabOrderby || options.sort;
panel.dataset.loadedTermId = String(options.termId);
}
@@ -374,12 +410,21 @@
return response.json();
})
.then(function (data) {
panel.innerHTML = '';
if (!options.append) panel.innerHTML = '';
markLoaded();
if (data && data.html) {
// 2. Inject HTML
panel.innerHTML = data.html;
// 2. Inject or append article nodes without nesting a posts-row wrapper.
if (options.append) {
var oldFooter = panel.querySelector('.aksrt-homepage__panel-footer');
if (oldFooter) oldFooter.remove();
var fragment = document.createElement('div');
fragment.innerHTML = data.html;
while (fragment.firstChild) panel.appendChild(fragment.firstChild);
} else {
panel.innerHTML = data.html;
}
renderPanelPager(panel, options, !!data.has_more);
// 3. Post-inject event
dispatchAfterEvent(panel, {
@@ -426,7 +471,9 @@
window.setTimeout(doFetch, 3000);
return;
}
panel.innerHTML = '';
if (!options.append) panel.innerHTML = '';
var failedFooter = panel.querySelector('.aksrt-homepage__panel-footer');
if (failedFooter) failedFooter.remove();
panel.appendChild(buildErrorState(panel, options));
});
}
@@ -535,9 +582,10 @@
});
});
// Mark server-rendered panels as already loaded
// Mark server-rendered panels as already loaded. The panel itself owns
// the posts-row contract, so checking descendants would miss SSR items.
panels.forEach(function (panel) {
if (!panel.querySelector('.aksrt-homepage__posts, .posts-row')) return;
if (getRenderedPostCount(panel) < 1) return;
panel.dataset.loaded = 'true';
panel.dataset.loadedPage = '1';
panel.dataset.loadedSort = getCurrentSort(stream);
@@ -736,16 +784,22 @@
* ============================================================ */
function applyViewMode(buttons, postsContainers, mode) {
buttons.forEach(function (btn) {
var btnMode = btn.getAttribute('data-view-mode');
btn.classList.toggle('is-active', btnMode === mode);
});
Array.prototype.forEach.call(postsContainers, function (container) {
container.setAttribute('data-view', mode);
});
}
buttons.forEach(function (btn) {
var btnMode = btn.getAttribute('data-view-mode');
var isActive = btnMode === mode;
btn.classList.toggle('is-active', isActive);
btn.setAttribute('aria-pressed', isActive ? 'true' : 'false');
});
Array.prototype.forEach.call(postsContainers, function (container) {
container.setAttribute('data-view', mode);
container.querySelectorAll('.posts-item').forEach(function (item) {
item.classList.toggle('card', mode === 'card');
item.classList.toggle('list', mode === 'list');
});
});
}
function initViewToggle() {
function initViewToggle() {
var toggles = document.querySelectorAll('[data-aksrt-view-toggle]');
toggles.forEach(function (toggle) {
@@ -754,7 +808,7 @@
if (!stream) return;
function getPostsContainers() {
return stream.querySelectorAll('.aksrt-homepage__posts, .posts-row');
return stream.querySelectorAll('[data-home-tab-panel]');
}
function getActiveMode() {
@@ -767,8 +821,21 @@
buttons.forEach(function (btn) {
btn.addEventListener('click', function () {
var mode = btn.getAttribute('data-view-mode') || getDefaultView();
applyViewMode(buttons, getPostsContainers(), mode);
var activePanel = getActivePanel(stream);
if (!activePanel || mode === getActiveMode()) return;
setViewMode(mode);
applyViewMode(buttons, getPostsContainers(), mode);
requestHomepagePanel(activePanel, {
termId: getPanelTermId(activePanel),
page: 1,
perPage: getHomepagePerPage(activePanel),
sort: getCurrentSort(stream),
viewMode: mode,
panel: activePanel.getAttribute('data-home-tab-panel') || 'latest',
source: 'home',
tabOrderby: getPanelTabOrderby(activePanel)
});
});
});