fix: 重写移动端文章目录生成逻辑
- 不再依赖 headIndex 插件,直接解析文章标题生成目录 - 独立实现目录树构建和 HTML 生成 - 独立实现滚动高亮更新逻辑 - 修复移动端目录为空的问题
This commit is contained in:
180
argontheme.js
180
argontheme.js
@@ -2511,7 +2511,6 @@ $(document).on("click" , "#blog_categories .tag" , function(){
|
|||||||
});
|
});
|
||||||
|
|
||||||
// ========== 移动端文章目录初始化 ==========
|
// ========== 移动端文章目录初始化 ==========
|
||||||
// 使用全局变量以便 PJAX 后重置
|
|
||||||
window.mobileCatalogInitialized = false;
|
window.mobileCatalogInitialized = false;
|
||||||
|
|
||||||
function initMobileCatalog() {
|
function initMobileCatalog() {
|
||||||
@@ -2521,105 +2520,105 @@ $(document).on("click" , "#blog_categories .tag" , function(){
|
|||||||
if ($mobileContainer.length === 0) return;
|
if ($mobileContainer.length === 0) return;
|
||||||
if ($postContent.length === 0) return;
|
if ($postContent.length === 0) return;
|
||||||
|
|
||||||
// 直接从桌面端目录复制内容,避免重复初始化 headIndex 导致的冲突
|
// 直接生成目录,不依赖 headIndex 插件
|
||||||
var $desktopCatalog = $("#leftbar_catalog");
|
var $headers = $postContent.find('h1, h2, h3, h4, h5, h6');
|
||||||
if ($desktopCatalog.length > 0 && $desktopCatalog.children().length > 0) {
|
if ($headers.length === 0) {
|
||||||
// 复制桌面端目录内容到移动端
|
$mobileContainer.html('<div class="no-catalog">暂无目录</div>');
|
||||||
$mobileContainer.html($desktopCatalog.html());
|
|
||||||
window.mobileCatalogInitialized = true;
|
|
||||||
|
|
||||||
// 绑定移动端目录的点击事件
|
|
||||||
$mobileContainer.off('click.mobileCatalog').on('click.mobileCatalog', '.index-link', function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
var targetId = $(this).attr('href');
|
|
||||||
if (targetId && targetId.startsWith('#')) {
|
|
||||||
var $target = $(targetId);
|
|
||||||
if ($target.length) {
|
|
||||||
// 更新高亮状态
|
|
||||||
$mobileContainer.find('.index-item').removeClass('current');
|
|
||||||
$(this).closest('.index-item').addClass('current');
|
|
||||||
|
|
||||||
// 滚动到目标位置
|
|
||||||
$('html, body').animate({
|
|
||||||
scrollTop: $target.offset().top - 80
|
|
||||||
}, 500, 'easeOutExpo');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 同步桌面端目录的高亮状态到移动端
|
|
||||||
syncMobileCatalogHighlight();
|
|
||||||
|
|
||||||
setTimeout(scrollMobileCatalogToActive, 150);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果桌面端目录不存在,则独立初始化移动端目录
|
// 构建目录树
|
||||||
var retryCount = 0;
|
var toc = [];
|
||||||
var maxRetries = 30;
|
var stack = [{ level: 0, children: toc }];
|
||||||
|
|
||||||
function tryInit() {
|
$headers.each(function(index) {
|
||||||
if (typeof jQuery !== 'undefined' && typeof jQuery.fn.headIndex === 'function') {
|
var $h = $(this);
|
||||||
// 使用一个临时的包装元素来初始化,避免与桌面端冲突
|
var level = parseInt(this.tagName.charAt(1));
|
||||||
var $wrapper = $('<div id="mobile_catalog_wrapper"></div>');
|
var text = $h.text().trim();
|
||||||
$wrapper.headIndex({
|
var id = $h.attr('id');
|
||||||
articleWrapSelector: '#post_content',
|
|
||||||
indexBoxSelector: '#leftbar_mobile_catalog',
|
// 确保标题有 ID
|
||||||
subItemBoxClass: "index-subItem-box",
|
if (!id) {
|
||||||
itemClass: "index-item",
|
id = 'mobile-heading-' + index;
|
||||||
linkClass: "index-link",
|
$h.attr('id', id);
|
||||||
offset: 80,
|
}
|
||||||
|
|
||||||
|
var item = { id: id, text: text, level: level, children: [] };
|
||||||
|
|
||||||
|
// 找到合适的父级
|
||||||
|
while (stack.length > 1 && stack[stack.length - 1].level >= level) {
|
||||||
|
stack.pop();
|
||||||
|
}
|
||||||
|
stack[stack.length - 1].children.push(item);
|
||||||
|
stack.push({ level: level, children: item.children });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 递归生成 HTML
|
||||||
|
function buildHtml(items, isRoot) {
|
||||||
|
if (!items || items.length === 0) return '';
|
||||||
|
var html = isRoot ? '<ul>' : '<ul class="index-subItem-box">';
|
||||||
|
for (var i = 0; i < items.length; i++) {
|
||||||
|
var item = items[i];
|
||||||
|
html += '<li class="index-item">';
|
||||||
|
html += '<a href="#' + item.id + '" class="index-link" data-target="' + item.id + '">' + item.text + '</a>';
|
||||||
|
if (item.children.length > 0) {
|
||||||
|
html += buildHtml(item.children, false);
|
||||||
|
}
|
||||||
|
html += '</li>';
|
||||||
|
}
|
||||||
|
html += '</ul>';
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
$mobileContainer.html(buildHtml(toc, true));
|
||||||
window.mobileCatalogInitialized = true;
|
window.mobileCatalogInitialized = true;
|
||||||
setTimeout(scrollMobileCatalogToActive, 150);
|
|
||||||
} else {
|
|
||||||
retryCount++;
|
|
||||||
if (retryCount < maxRetries) {
|
|
||||||
setTimeout(tryInit, 100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setTimeout(tryInit, 50);
|
// 绑定点击事件
|
||||||
}
|
$mobileContainer.off('click.mobileCatalog').on('click.mobileCatalog', '.index-link', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
// 同步桌面端目录高亮状态到移动端
|
var targetId = $(this).attr('href');
|
||||||
function syncMobileCatalogHighlight() {
|
if (targetId) {
|
||||||
var $desktopCatalog = $("#leftbar_catalog");
|
var $target = $(targetId);
|
||||||
var $mobileContainer = $("#leftbar_mobile_catalog");
|
if ($target.length) {
|
||||||
|
|
||||||
if ($desktopCatalog.length === 0 || $mobileContainer.length === 0) return;
|
|
||||||
|
|
||||||
// 监听桌面端目录的高亮变化
|
|
||||||
var observer = new MutationObserver(function(mutations) {
|
|
||||||
mutations.forEach(function(mutation) {
|
|
||||||
if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
|
|
||||||
var $target = $(mutation.target);
|
|
||||||
if ($target.hasClass('index-item')) {
|
|
||||||
var href = $target.find('> .index-link').attr('href');
|
|
||||||
if (href) {
|
|
||||||
// 同步高亮状态到移动端
|
|
||||||
$mobileContainer.find('.index-item').removeClass('current');
|
$mobileContainer.find('.index-item').removeClass('current');
|
||||||
$mobileContainer.find('.index-link[href="' + href + '"]').closest('.index-item').addClass('current');
|
$(this).closest('.index-item').addClass('current');
|
||||||
|
$('html, body').animate({
|
||||||
|
scrollTop: $target.offset().top - 80
|
||||||
|
}, 500, 'easeOutExpo');
|
||||||
|
// 点击后关闭侧边栏
|
||||||
|
setTimeout(function() {
|
||||||
|
$("html").removeClass("leftbar-opened");
|
||||||
|
}, 150);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
observer.observe($desktopCatalog[0], {
|
// 初始化高亮并启动滚动监听
|
||||||
attributes: true,
|
updateMobileCatalogHighlight();
|
||||||
subtree: true,
|
setTimeout(scrollMobileCatalogToActive, 150);
|
||||||
attributeFilter: ['class']
|
}
|
||||||
|
|
||||||
|
// 更新移动端目录高亮
|
||||||
|
function updateMobileCatalogHighlight() {
|
||||||
|
var $mobileContainer = $("#leftbar_mobile_catalog");
|
||||||
|
var $postContent = $("#post_content");
|
||||||
|
if ($mobileContainer.length === 0 || $postContent.length === 0) return;
|
||||||
|
|
||||||
|
var scrollTop = $(window).scrollTop();
|
||||||
|
var $headers = $postContent.find('h1, h2, h3, h4, h5, h6');
|
||||||
|
var currentId = null;
|
||||||
|
|
||||||
|
$headers.each(function() {
|
||||||
|
var $h = $(this);
|
||||||
|
var top = $h.offset().top - 100;
|
||||||
|
if (scrollTop >= top) {
|
||||||
|
currentId = $h.attr('id');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 初始同步当前高亮状态
|
if (currentId) {
|
||||||
var $currentItem = $desktopCatalog.find('.index-item.current');
|
$mobileContainer.find('.index-item').removeClass('current');
|
||||||
if ($currentItem.length > 0) {
|
$mobileContainer.find('.index-link[href="#' + currentId + '"]').closest('.index-item').addClass('current');
|
||||||
var href = $currentItem.find('> .index-link').attr('href');
|
|
||||||
if (href) {
|
|
||||||
$mobileContainer.find('.index-link[href="' + href + '"]').closest('.index-item').addClass('current');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2653,6 +2652,8 @@ $(document).on("click" , "#blog_categories .tag" , function(){
|
|||||||
if (mobileCatalogScrollTimer) return;
|
if (mobileCatalogScrollTimer) return;
|
||||||
mobileCatalogScrollTimer = setTimeout(function() {
|
mobileCatalogScrollTimer = setTimeout(function() {
|
||||||
mobileCatalogScrollTimer = null;
|
mobileCatalogScrollTimer = null;
|
||||||
|
// 更新高亮状态
|
||||||
|
updateMobileCatalogHighlight();
|
||||||
// 只在侧边栏打开且目录展开时滚动
|
// 只在侧边栏打开且目录展开时滚动
|
||||||
if ($("html").hasClass("leftbar-opened") &&
|
if ($("html").hasClass("leftbar-opened") &&
|
||||||
$("#mobile_catalog_toggle").closest(".leftbar-mobile-collapse-section").hasClass("expanded")) {
|
$("#mobile_catalog_toggle").closest(".leftbar-mobile-collapse-section").hasClass("expanded")) {
|
||||||
@@ -2661,12 +2662,7 @@ $(document).on("click" , "#blog_categories .tag" , function(){
|
|||||||
}, 150);
|
}, 150);
|
||||||
});
|
});
|
||||||
|
|
||||||
// 点击目录项后关闭侧边栏
|
// 点击目录项后关闭侧边栏(已在 initMobileCatalog 中处理)
|
||||||
$(document).on("click", "#leftbar_mobile_catalog .index-link", function() {
|
|
||||||
setTimeout(function() {
|
|
||||||
$("html").removeClass("leftbar-opened");
|
|
||||||
}, 150);
|
|
||||||
});
|
|
||||||
|
|
||||||
// ========== 移动端TODO交互 ==========
|
// ========== 移动端TODO交互 ==========
|
||||||
function updateMobileTodoCount() {
|
function updateMobileTodoCount() {
|
||||||
|
|||||||
Reference in New Issue
Block a user