Created
June 11, 2017 14:16
-
-
Save prinsss/ecddd370f07fbab69e4bf9c36085c54c to your computer and use it in GitHub Desktop.
依赖于 jQuery 的纯前端生成文章目录(Table of Contents)。本来是为了辣鸡 Ghost 博客写的,可惜我现在要投奔 Hexo 了 ( ̄3 ̄)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 差不多就是把一些项目中的现有代码黏在一起,能用而已。目前实现的功能有: | |
* | |
* - 生成 TOC(废话) | |
* - 滚动监听(高亮当前项目) | |
* - 点击跳转 | |
*/ | |
// https://github.com/ghiculescu/jekyll-table-of-contents | |
(function($){ | |
$.fn.toc = function (options) { | |
var defaults = { | |
noBackToTopLinks: false, | |
title: '<i>Jump to...</i>', | |
minimumHeaders: 3, | |
scope: 'body', | |
selector: 'h1, h2, h3, h4, h5, h6', | |
overwrite: true, // generate new IDs for header elements | |
listType: 'ol', // values: [ol|ul] | |
showEffect: 'show', // values: [show|slideDown|fadeIn|none] | |
showSpeed: 'slow', // set to 0 to deactivate effect | |
classes: { list: '', item: '' } | |
}, | |
options = $.extend(defaults, options); | |
function fixedEncodeURIComponent(str) { | |
return encodeURIComponent(str).replace(/[!'()*]/g, function(c) { | |
return '%' + c.charCodeAt(0).toString(16); | |
}); | |
} | |
function createLink(header) { | |
var innerText = (header.textContent === undefined) ? header.innerText : header.textContent; | |
return "<a href='#" + fixedEncodeURIComponent(header.id) + "'>" + innerText + "</a>"; | |
} | |
if (options.overwrite) { | |
var i = 0; | |
$(options.scope).find(options.selector).each(function () { | |
$(this).attr('id', 'article-title-' + i); | |
i++; | |
}); | |
} | |
var headers = $(options.scope).find(options.selector).filter(function () { | |
// get all headers with an ID | |
var previousSiblingName = $(this).prev().attr( "name" ); | |
if (!this.id && previousSiblingName) { | |
this.id = $(this).attr( "id", previousSiblingName.replace(/\./g, "-") ); | |
} | |
return this.id; | |
}), output = $(this); | |
if (!headers.length || headers.length < options.minimumHeaders || !output.length) { | |
$(this).hide(); | |
return; | |
} | |
if (0 === options.showSpeed) { | |
options.showEffect = 'none'; | |
} | |
var render = { | |
show: function() { output.hide().html(html).show(options.showSpeed); }, | |
slideDown: function() { output.hide().html(html).slideDown(options.showSpeed); }, | |
fadeIn: function() { output.hide().html(html).fadeIn(options.showSpeed); }, | |
none: function() { output.html(html); } | |
}; | |
var get_level = function(ele) { return parseInt(ele.nodeName.replace("H", ""), 10); }; | |
var highest_level = headers.map(function(_, ele) { return get_level(ele); }).get().sort()[0]; | |
var return_to_top = '<i class="icon-arrow-up back-to-top"> </i>'; | |
var level = get_level(headers[0]), | |
this_level, | |
html = options.title + " <" +options.listType + " class=\"" + options.classes.list +"\">"; | |
headers.on('click', function() { | |
if (!options.noBackToTopLinks) { | |
window.location.hash = this.id; | |
} | |
}) | |
.addClass('clickable-header') | |
.each(function(_, header) { | |
this_level = get_level(header); | |
if (!options.noBackToTopLinks && this_level === highest_level) { | |
$(header).addClass('top-level-header').after(return_to_top); | |
} | |
if (this_level === level) // same level as before; same indenting | |
html += "<li class=\"" + options.classes.item + "\">" + createLink(header); | |
else if (this_level <= level){ // higher level than before; end parent ol | |
for(var i = this_level; i < level; i++) { | |
html += "</li></"+options.listType+">" | |
} | |
html += "<li class=\"" + options.classes.item + "\">" + createLink(header); | |
} | |
else if (this_level > level) { // lower level than before; expand the previous to contain a ol | |
for(i = this_level; i > level; i--) { | |
html += "<" + options.listType + " class=\"" + options.classes.list +"\">" + | |
"<li class=\"" + options.classes.item + "\">" | |
} | |
html += createLink(header); | |
} | |
level = this_level; // update for the next one | |
}); | |
html += "</"+options.listType+">"; | |
if (!options.noBackToTopLinks) { | |
$(document).on('click', '.back-to-top', function() { | |
$(window).scrollTop(0); | |
window.location.hash = ''; | |
}); | |
} | |
render[options.showEffect](); | |
return this; | |
}; | |
})(jQuery); | |
/** | |
* jQuery lightweight plugin boilerplate | |
* | |
* @file_name jquery.navScrollSpy.js | |
* @author liuyidi <[email protected]> | |
* Licensed under the MIT license | |
* | |
* example: | |
* <ul id="nav"> | |
* <li class="active"><a href="#box1">box1</a></li> | |
* <li><a href="#box2">box2</a></li> | |
* </ul> | |
* | |
* $("#nav").navScrollSpy({ | |
* active:"", | |
* scrollSpeed: 750 | |
* }); | |
* | |
* 滚动监听 点击切换 平滑滚动 | |
*/ | |
;(function ($, window, document, undefined) { | |
// pluginName | |
var pluginName = "navScrollSpy"; | |
// defaults options | |
var defaults = { | |
navContainer: '#nav', // 外部容器 | |
navItems: 'a', // 元素 | |
active : 'active', // 当前 | |
easing : 'swing', // 动效 | |
speed: 550 // 速度 | |
}; | |
function navScrollSpy (element, options) { | |
this.element = element; | |
this.options = $.extend({}, defaults, options); | |
this.$ele = $(element); // 获得 $("#nav") | |
this.$win = $(window); // 获取 window | |
this._defaults = defaults; | |
this._name = pluginName; | |
this.anchorItems = {}; | |
this.init(); | |
}; | |
navScrollSpy.prototype = { | |
init: function() { | |
this.navItems = this.$ele.find(this.options.navItems); | |
this.anchorItems = this.getAnchorItems(this.navItems); | |
// 点击切换导航按钮样式, 更改上下文 this | |
this.navItems.on("click", $.proxy(this.clickSwitch, this)); | |
// 滚动切换导航按钮 | |
this.$win.on("scroll", $.proxy(this.scrolling, this)); | |
return this; | |
}, | |
getAnchorItems: function (navItems) { | |
var items = []; | |
// find items in selected element | |
navItems.each(function () { | |
var id = $(this).attr('href').split('#')[1]; | |
items[id] = { | |
// get the offset top of anchor element with corresponding id | |
top: $('#' + id).offset().top, | |
height: $(this).height(), | |
elem: this | |
}; | |
}); | |
return items; | |
}, | |
// 导航变化 | |
active: function(self, parent) { | |
var active = self.options.active; | |
self.$ele.find("."+active).removeClass(active); | |
parent.addClass(active); | |
}, | |
// 滚动切换 | |
scrolling: function () { | |
// var st = $(window).scrollTop(); | |
// var wH = $(window).height(); | |
// 临界条件: $("#id").offset().top-$(window).scrollTop()>$(window).height()/2; | |
for (var id in this.anchorItems) { | |
var item = this.anchorItems[id]; | |
// if(st >= this.boxs[box]-parseInt(wH/2)){ | |
if ($(window).scrollTop() >= item.top - item.height / 3) { | |
var parent = this.$ele.find('a[href="#'+id+'"]').parent(); | |
this.active(this, parent); | |
} | |
}; | |
}, | |
// 点击切换 | |
clickSwitch: function(e) { | |
var navItemClicked = $(e.currentTarget); // 获得当前的 a | |
var parent = navItemClicked.parent(); // 获得 a 的 li 元素 | |
var self = this; | |
var target = navItemClicked.attr('href').split('#')[1]; // 新的 a #id | |
if (!parent.hasClass(self.options.active)) { | |
// 导航切换 | |
self.active(self, parent); | |
// 滚动开始 | |
self.scrollTo(target, function(){ | |
//callback | |
}); | |
} | |
e.preventDefault(); // 有 active 阻止冒泡 | |
}, | |
// 滚动到某个地方 | |
scrollTo: function(target, callback){ | |
// 获取目标元素的 TOP 值 | |
var offsetTop = this.anchorItems[target].top; | |
var $el = $('html,body'); | |
if (!$el.is(":animated")) { | |
$el.animate({ | |
scrollTop: offsetTop | |
}, this.options.speed, this.options.easing,callback); | |
} | |
} | |
}; | |
$.fn.navScrollSpy = function(options) { | |
return this.each(function () { | |
if(!$.data(this, "plugin_"+pluginName)){ | |
$.data(this, "plugin_"+pluginName,new navScrollSpy(this, options)); | |
} | |
}); | |
}; | |
})(jQuery, window, document); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 示例,$('#toc') 为 TOC 容器,在 '.post-content' 中检索并生成目录 | |
$('#toc').toc({ | |
scope: '.post-content' | |
}).navScrollSpy({ | |
navContainer: '#toc' | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 自定义样式 */ | |
#toc ol { | |
list-style: none; | |
} | |
#toc ol li a { | |
color: inherit; | |
} | |
#toc ol li.active > a:first-child { | |
color: #009553; /* 高亮当前项 */ | |
} | |
#toc ol li, #toc ol li a { | |
overflow-x: hidden; | |
text-overflow: ellipsis; | |
-o-text-overflow: ellipsis; | |
white-space: nowrap; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment