orgen-theme/assets/vendor/headindex/headindex.js
2023-04-06 16:58:33 +08:00

353 lines
14 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;(function ($, window) {
var headIndex = (function () {
function headIndex(element, options) {
this.settings = $.extend(true, $.fn.headIndex.default, options || {});
this.element = element;
this.init();
}
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;
if (this.indexBox.length === 0 || this.headerList.length === 0) {
return null;
}
this.initHeader();
this.event();
},
initHeader: function () {
for (var i = 0; i < this.headerList.length; i++, this.autoId++) {
//文章header添加id和计算高度
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 = '<ul>' + this.tempHtml.join('') + '</ul>';
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'))
}
});
//鼠标 Hover 监听
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;
}
//第一个和最后一个标题的高度变化的差值相同,默认整体标题的变化差值相同
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;
}
//移除其他位置的current类
var otherCurrent = this.indexBox.find('li.' + currentClass);
if (otherCurrent.length > 0) {
otherCurrent.removeClass(currentClass);
}
//先清除全部的open标记
this.indexBox.find('ul.open').removeClass('open');
//打开当前下级别的subItemBox
subBox = indexItem.children('.' + this.settings.subItemBoxClass);
if (subBox.length > 0) {
subBox.addClass('open').slideDown();
}
//为了应对非常快速滑动的时候scroll函数略过父级的box
var parentsBox = indexItem.parents('ul.' + this.settings.subItemBoxClass);
if (parentsBox.length > 0) {
parentsBox.addClass('open').slideDown()
}
//关闭其他位置打开的subItemBox 排除当前父级上的subItemBox
subBox = this.indexBox.find('ul.' + this.settings.subItemBoxClass).not('.open');
if (subBox.length > 0) {
subBox.slideUp()
}
//为当前添加current类
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');
}
if (relativeOffsetTopToWrapper > indexScrollBoxHeight - 10){
this.indexScrollBox.stop().animate({
scrollTop: indexScrollBoxScrollTop + relativeOffsetTopToWrapper - indexScrollBoxHeight + 10 + indexItem.height()
}, 'normal');
}
},
buildHtml: function (tree) {
if (tree === undefined || tree.length === 0) return;
for (var i = 0; i < tree.length; i++) {
this.tempHtml.push("<li class='" + this.settings.itemClass + "'>"
+ "<a no-pjax class='" + this.settings.linkClass + "' href='#" + tree[i].item.id + "'>"
+ tree[i].item.innerText + "</a>");
if (tree[i].children.length !== 0) {
this.tempHtml.push("<ul class='" + this.settings.subItemBoxClass + "'>");
this.buildHtml(tree[i].children);
this.tempHtml.push("</ul>");
}
this.tempHtml.push("</li>")
}
},
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)
}
},
/**
* 计算每个标题距离文档顶部的垂直高度,
* 为了应对不同需求,如果计算不准确,可以修改这个方法
* @param elem
* @returns {number}
*/
/*已重写该方法*/
offsetTop: function (elem) {
return $(elem).offset().top - this.settings.offset;
/*var wrapTop = this.articleWrap[0].getBoundingClientRect().top
var eTop = elem.getBoundingClientRect().top
return parseInt(eTop - wrapTop - this.settings.offset)*/
// var rect, win;
// if (!elem) {
// return;
// }
// if (!elem.getClientRects().length) {
// return {top: 0, left: 0};
// }
//
// rect = elem.getBoundingClientRect();
// win = elem.ownerDocument.defaultView;
// return parseInt(rect.top + win.pageYOffset);
},
/**
* 滑动到指定id选择器的标题
* @param eid 标题的id值
*/
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");
/*此处为适配 pjax 注释了下面的 if*/
/*if (!instance) {*/
instance = new headIndex($this, options);
$this.data("headIndex", instance);
/*}*/
if ($.type(options) === "string") return instance[options]();
});
};
//-----------------------------------
// 默认参数
//-----------------------------------
$.fn.headIndex.default = {
articleWrapSelector: ".article-wrap",/*包裹文章的选择器*/
indexBoxSelector: ".index-box",/*包裹目录索引的选择器*/
indexScrollBoxSelector: "#leftbar_part2_inner",/*包裹目录索引的选择器 (新增)*/
scrollSelector: 'body,html',/*滑动元素的选择器*/
scrollWrap: window,/*能够监听到scrollSelector滑动的选择器*/
subItemBoxClass: "index-subItem-box",
itemClass: "index-item",
linkClass: "index-link",
offset: 0,/*滑动偏移量 按需求进行偏移*/
}
})(jQuery, window);