diff --git a/argontheme.js b/argontheme.js index d9cc864..c85c2e4 100644 --- a/argontheme.js +++ b/argontheme.js @@ -2516,15 +2516,53 @@ $(document).on("click" , "#blog_categories .tag" , function(){ function initMobileCatalog() { if (window.mobileCatalogInitialized) return; - if ($("#leftbar_mobile_catalog").length === 0) return; - if ($("#post_content").length === 0) return; + var $mobileContainer = $("#leftbar_mobile_catalog"); + var $postContent = $("#post_content"); + if ($mobileContainer.length === 0) return; + if ($postContent.length === 0) return; + // 直接从桌面端目录复制内容,避免重复初始化 headIndex 导致的冲突 + var $desktopCatalog = $("#leftbar_catalog"); + if ($desktopCatalog.length > 0 && $desktopCatalog.children().length > 0) { + // 复制桌面端目录内容到移动端 + $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; + } + + // 如果桌面端目录不存在,则独立初始化移动端目录 var retryCount = 0; var maxRetries = 30; function tryInit() { if (typeof jQuery !== 'undefined' && typeof jQuery.fn.headIndex === 'function') { - jQuery(document).headIndex({ + // 使用一个临时的包装元素来初始化,避免与桌面端冲突 + var $wrapper = $('
'); + $wrapper.headIndex({ articleWrapSelector: '#post_content', indexBoxSelector: '#leftbar_mobile_catalog', subItemBoxClass: "index-subItem-box", @@ -2533,7 +2571,6 @@ $(document).on("click" , "#blog_categories .tag" , function(){ offset: 80, }); window.mobileCatalogInitialized = true; - // 初始化后滚动到当前位置 setTimeout(scrollMobileCatalogToActive, 150); } else { retryCount++; @@ -2546,6 +2583,46 @@ $(document).on("click" , "#blog_categories .tag" , function(){ setTimeout(tryInit, 50); } + // 同步桌面端目录高亮状态到移动端 + function syncMobileCatalogHighlight() { + var $desktopCatalog = $("#leftbar_catalog"); + var $mobileContainer = $("#leftbar_mobile_catalog"); + + 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-link[href="' + href + '"]').closest('.index-item').addClass('current'); + } + } + } + }); + }); + + observer.observe($desktopCatalog[0], { + attributes: true, + subtree: true, + attributeFilter: ['class'] + }); + + // 初始同步当前高亮状态 + var $currentItem = $desktopCatalog.find('.index-item.current'); + if ($currentItem.length > 0) { + var href = $currentItem.find('> .index-link').attr('href'); + if (href) { + $mobileContainer.find('.index-link[href="' + href + '"]').closest('.index-item').addClass('current'); + } + } + } + // 重置移动端目录状态(供 PJAX 调用) window.resetMobileCatalog = function() { window.mobileCatalogInitialized = false; diff --git a/assets/vendor/headindex/headindex.js b/assets/vendor/headindex/headindex.js index 5c3e5da..1490722 100644 --- a/assets/vendor/headindex/headindex.js +++ b/assets/vendor/headindex/headindex.js @@ -1,126 +1,320 @@ /*! * headIndex.js - 文章目录生成插件 * 为 Argon 主题提供文章目录功能 + * + * 注意:此文件仅用于后台设置页面预览 + * 前端页面使用的是 argon_js_merged.js 中的压缩版本 */ -(function($) { - 'use strict'; - - $.fn.headIndex = function(options) { - var defaults = { - articleWrapSelector: '#post_content', - indexBoxSelector: '#leftbar_catalog', - subItemBoxClass: 'index-subItem-box', - scrollOffset: 80, - activeClass: 'active' - }; - - var settings = $.extend({}, defaults, options); - var $articleWrap = $(settings.articleWrapSelector); - var $indexBox = $(settings.indexBoxSelector); - - if (!$articleWrap.length || !$indexBox.length) { - return this; +;(function($, window) { + var headIndex = (function() { + function headIndex(element, options) { + this.settings = $.extend(true, $.fn.headIndex.default, options || {}); + this.element = element; + this.init(); } - - // 查找所有标题元素 - var $headings = $articleWrap.find('h1, h2, h3, h4, h5, h6'); - if ($headings.length === 0) { - $indexBox.html('
暂无目录
'); - return this; - } - - // 生成目录HTML - var indexHtml = ''; - - $indexBox.html(indexHtml); - - // 绑定点击事件 - $indexBox.on('click', '.catalog-link', function(e) { - e.preventDefault(); - var targetId = $(this).data('target'); - var $target = $('#' + targetId); - - if ($target.length) { - $('html, body').animate({ - scrollTop: $target.offset().top - settings.scrollOffset - }, 500, 'easeOutExpo'); + headIndex.prototype = { + init: function() { + this.articleWrap = $(this.settings.articleWrapSelector); + this.headerList = this.articleWrap.find(':header'); + this.indexBox = $(this.settings.indexBoxSelector); + this.indexScrollBox = $(this.settings.indexScrollBoxSelector); + this.scrollBody = $(this.settings.scrollSelector); + this.scrollWrap = $(this.settings.scrollWrap); + this.manual = false; + this.mouseHovered = false; - // 更新活动状态 - $indexBox.find('.catalog-link').removeClass(settings.activeClass); - $(this).addClass(settings.activeClass); - } - }); - - // 滚动时高亮当前章节 - var throttleTimer = null; - $(window).on('scroll', function() { - if (throttleTimer) { - clearTimeout(throttleTimer); - } - - throttleTimer = setTimeout(function() { - var scrollTop = $(window).scrollTop(); - var currentHeading = null; + if (this.indexBox.length === 0 || this.headerList.length === 0) { + return null; + } - $headings.each(function() { - var $heading = $(this); - var headingTop = $heading.offset().top - settings.scrollOffset - 50; - - if (scrollTop >= headingTop) { - currentHeading = $heading.attr('id'); + this.initHeader(); + this.event(); + }, + + initHeader: function() { + for (var i = 0; i < this.headerList.length; i++, this.autoId++) { + this.headerList[i].id = this.headerList[i].id || "header-id-" + this.autoId; + this.headerList[i].topHeight = this.offsetTop(this.headerList[i]); + this.headerList[i].h = Number(this.headerList[i].tagName.charAt(1)); + } + + this.tempHtml = []; + this.buildHtml(this.buildTree()); + var res = ''; + this.indexBox.html(res); + }, + + event: function() { + var that = this; + var manualValTimer = null; + + this.indexBox.on('click.headindex', function(event) { + var target = $(event.target); + if (target.hasClass(that.settings.linkClass)) { + event.preventDefault(); + var indexItem = target.parent('.' + that.settings.itemClass); + that.manual = true; + if (manualValTimer) { + clearTimeout(manualValTimer); + manualValTimer = null; + } + manualValTimer = setTimeout(function() { + that.manual = false; + }, 400); + that.current(indexItem); + that.scrollTo(event.target.getAttribute('href')); } }); - if (currentHeading) { - $indexBox.find('.catalog-link').removeClass(settings.activeClass); - $indexBox.find('.catalog-link[data-target="' + currentHeading + '"]').addClass(settings.activeClass); + this.indexScrollBox.on('mouseover', function(event) { + that.mouseHovered = true; + }); + + this.indexScrollBox.on('mouseleave', function(event) { + that.mouseHovered = false; + }); + + $(this.scrollWrap).scroll(function() { + if (that.manual) return; + that.updateCurrent(); + }); + + that.updateCurrent(); + }, + + updateTopHeight: function() { + var length = this.headerList.length; + var i; + if (length === 0) return; + + if (this.headerList[0].topHeight === this.offsetTop(this.headerList[0]) && + this.headerList[length - 1].topHeight === this.offsetTop(this.headerList[length - 1])) { + return; } - }, 100); + + if ((this.headerList[0].topHeight - this.offsetTop(this.headerList[0])) === + (this.headerList[length - 1].topHeight - this.offsetTop(this.headerList[length - 1]))) { + var hx = this.offsetTop(this.headerList[0]) - this.headerList[0].topHeight; + for (i = 0; i < this.headerList.length; i++, this.autoId++) { + this.headerList[i].topHeight += hx; + } + return; + } + + for (i = 0; i < this.headerList.length; i++, this.autoId++) { + this.headerList[i].topHeight = this.offsetTop(this.headerList[i]); + } + }, + + current: function(indexItem) { + var subBox, currentClass = 'current'; + if (indexItem.length === 0 || indexItem.hasClass(currentClass)) { + return; + } + + var otherCurrent = this.indexBox.find('li.' + currentClass); + if (otherCurrent.length > 0) { + otherCurrent.removeClass(currentClass); + } + + this.indexBox.find('ul.open').removeClass('open'); + subBox = indexItem.children('.' + this.settings.subItemBoxClass); + if (subBox.length > 0) { + subBox.addClass('open').slideDown(); + } + + var parentsBox = indexItem.parents('ul.' + this.settings.subItemBoxClass); + if (parentsBox.length > 0) { + parentsBox.addClass('open').slideDown(); + } + + subBox = this.indexBox.find('ul.' + this.settings.subItemBoxClass).not('.open'); + if (subBox.length > 0) { + subBox.slideUp(); + } + + indexItem.addClass(currentClass); + + if (this.mouseHovered) { + return; + } + + var relativeOffsetTopToWrapper = indexItem.position().top; + var indexScrollBoxScrollTop = this.indexScrollBox.scrollTop(); + var indexScrollBoxHeight = this.indexScrollBox.height(); + + if (relativeOffsetTopToWrapper < 20 + indexItem.height()) { + var target = indexScrollBoxScrollTop + relativeOffsetTopToWrapper - 20 - indexItem.height(); + if (target < 30) { + target = 0; + } + this.indexScrollBox.stop().animate({scrollTop: target}, 'normal', 'easeOutExpo'); + } + + if (relativeOffsetTopToWrapper > indexScrollBoxHeight - 10) { + this.indexScrollBox.stop().animate({ + scrollTop: indexScrollBoxScrollTop + relativeOffsetTopToWrapper - indexScrollBoxHeight + 10 + indexItem.height() + }, 'normal', 'easeOutExpo'); + } + }, + + buildHtml: function(tree) { + if (tree === undefined || tree.length === 0) return; + + for (var i = 0; i < tree.length; i++) { + this.tempHtml.push("
  • " + tree[i].item.innerText + ""); + if (tree[i].children.length !== 0) { + this.tempHtml.push(""); + } + this.tempHtml.push("
  • "); + } + }, + + buildTree: function() { + var current = null, tempCur, indexTree = []; + + for (var i = 0; i < this.headerList.length; i++) { + if (current == null) { + current = { + item: this.headerList[i], + parent: null, + children: [] + }; + indexTree.push(current); + continue; + } + + if (current.item.h < this.headerList[i].h) { + tempCur = { + item: this.headerList[i], + parent: current, + children: [] + }; + current.children.push(tempCur); + current = tempCur; + continue; + } + + if (current.item.h === this.headerList[i].h) { + tempCur = { + item: this.headerList[i], + parent: current.parent, + children: [] + }; + ((current.parent && current.parent.children) || indexTree).push(tempCur); + current = tempCur; + continue; + } + + while (current != null && current.item.h > this.headerList[i].h) { + current = current.parent; + } + + if (current == null) { + current = { + item: this.headerList[i], + parent: null, + children: [] + }; + indexTree.push(current); + continue; + } + i--; + } + + return indexTree; + }, + + search: function(start, end, findValue) { + if (this.headerList.length === 0) return null; + + if (end - start <= 1) { + if (this.headerList[end].topHeight < findValue) { + return this.headerList[end]; + } + return this.headerList[start]; + } + + if (start < end) { + var middleIndex = parseInt((start + end) / 2); + var middleValue = this.headerList[middleIndex].topHeight; + + if (findValue < middleValue) { + end = middleIndex; + } else if (findValue > middleValue) { + start = middleIndex; + } else { + return this.headerList[middleIndex]; + } + return this.search(start, end, findValue); + } + }, + + offsetTop: function(elem) { + return $(elem).offset().top - this.settings.offset; + }, + + scrollTo: function(eid) { + this.scrollBody.stop().animate({ + scrollTop: this.offsetTop(document.getElementById(eid.substr(1))) + 8 + }, 'normal', 'easeOutExpo'); + }, + + updateCurrent: function() { + var scrollTop = this.scrollBody.scrollTop(); + this.updateTopHeight(); + var find = this.search(0, this.headerList.length - 1, scrollTop); + if (!find) { + return; + } + var indexItem = this.indexBox.find('a[href="#' + find.id + '"]').parent('li.' + this.settings.itemClass); + this.current(indexItem); + }, + + clean: function() { + if (this.element) { + this.element.data("headIndex", null); + } + }, + + ignoreScrollEvent: function(ignore) { + if (ignore) { + this.manual = true; + } else { + this.manual = false; + this.updateCurrent(); + } + } + }; + + headIndex.prototype.autoId = 1; + + return headIndex; + })(); + + $.fn.headIndex = function(options) { + return this.each(function() { + var $this = $(this), + instance = $this.data("headIndex"); + instance = new headIndex($this, options); + $this.data("headIndex", instance); + if ($.type(options) === "string") return instance[options](); }); - - return this; }; - -})(jQuery); \ No newline at end of file + + $.fn.headIndex.default = { + articleWrapSelector: ".article-wrap", + indexBoxSelector: ".index-box", + indexScrollBoxSelector: "#leftbar_part2_inner", + scrollSelector: 'body,html', + scrollWrap: window, + subItemBoxClass: "index-subItem-box", + itemClass: "index-item", + linkClass: "index-link", + offset: 0 + }; + +})(jQuery, window);