菜鸡通过改造博客园学习前端(添加目录)
时间:2020-04-09
本文章向大家介绍菜鸡通过改造博客园学习前端(添加目录),主要包括菜鸡通过改造博客园学习前端(添加目录)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
下面主要介绍的内容是,给博客园添加一个目录
- 需要兼容 markdown 和 TinyMCE 编辑器
- 给标题添加活跃样式
- 可选的固定位置
如有错误或不足,欢迎指正!
可选的配置
catalog: {
enable: true,
position: 'left',
},
- enable 是否弃用
- position 目录固定的位置
- left 固定在左侧
- right 固定在右侧
- sidebar '类似掘金文章目录固定效果的效果'
插件结构
我把文章目录作为一个 plugin 集成到项目中,下面是这个插件的基本结构,放在这里方便你理清思路。
import { pageName, userAgent, hasPostTitle, getClientRect, throttle } from '@tools'
const { enable, position } = opts.catalog
// 在这里写几个 func
function catalog() {
if (conditions) return // 在入口处做一些基本的判断
// 在这里执行上面的 func
}
export default catalog
import
- pageName 返回当前页面名称,如果不是文章详情页则不必执行代码
- userAgent 返回用户客户端类型,移动端无需文章目录
- hasPostTitle 返回当前文章是否存在文章标题
- getClientRect 返回元素相对与浏览器视口的位置
构建 html
思路:遍历博客园随笔内容子元素 DOM,通过正则表达式获取标题,创建目录 html 元素,并添加锚点链接。由于非 markdown 编辑器的标题没有 id,需要在遍历时添加 id,其值即为标题。非 markdown 编辑器的标题内容可能不直接被 h123 标签所嵌套, 稍微判断处理即可。
function build() {
let $catalogContainer = $(
`<div id="catalog">
<div class='catListTitle'><h3>目录</h3></div>
</div>`
)
const $ulContainer = $('<ul></ul>')
const titleRegExp = /^h[1-3]$/
$('#cnblogs_post_body')
.children()
.each(function () {
if (titleRegExp.test(this.tagName.toLowerCase())) {
let id
let text
if (this.id !== '') {
id = this.id
text = this.childNodes.length === 2 ? this.childNodes[1].nodeValue : this.childNodes[0].nodeValue
} else {
if (this.childNodes.length === 2) {
const value = this.childNodes[1].nodeValue
text = value ? value : $(this.childNodes[1]).text()
} else {
const value = this.childNodes[0].nodeValue
text = value ? value : $(this.childNodes[0]).text()
}
id = text.trim()
$(this).attr('id', id)
}
const title = `
<li class='${this.nodeName.toLowerCase()}-list'>
<a href='#${id}'>${text}</a>
</li>
`
$ulContainer.append(title)
}
})
$($catalogContainer.append($ulContainer)).appendTo('#sideBar')
setCatalogPosition()
}
固定目录
接下来根据用户配置的 position,将目录固定在指定位置。
function setCatalogPosition() {
const actions = {
sidebar: () => {
setCatalogToggle()
},
left: () => {
$('#catalog').addClass('catalog-sticky-left')
},
right: () => {
$('#catalog').addClass('catalog-sticky-right')
},
}
actions[position]()
}
可以采用更为简洁的写法, 这里考虑扩展性, 采用这种写法。
处理固定在侧栏的情况
目录固定在侧栏时,原来的侧边栏滚动到不可见位置才显示目录,很简单,我们只需要监听滚动事件,获取原侧栏高度,当它超出屏幕,则固定目录。反之,则相反。
function setCatalogToggle() {
if (position !== 'sidebar') return
var p = 0,
t = 0
$(window).scroll(
throttle(
function () {
const bottom = getClientRect(document.querySelector('#sideBarMain')).bottom
if (bottom <= 0) {
$('#catalog').addClass('catalog-sticky')
p = $(this).scrollTop()
t <= p ? $('#catalog').addClass('catalog-scroll-up') : $('#catalog').removeClass('catalog-scroll-up')
setTimeout(function () {
t = p
}, 0)
} else {
$('#catalog').removeClass('catalog-sticky')
}
},
50,
1000 / 60
)
)
}
给标题添加活跃样式
这一步实现思路和处理固定在侧栏的情况基本一致,当一个文章目录超出屏幕时,我们给对应的标题添加活跃的样式就可以了。
function setActiveCatalogTitle() {
$(window).scroll(
throttle(
function () {
for (let i = $('#catalog ul li').length - 1; i >= 0; i--) {
const titleId = $($('#catalog ul li')[i]).find('a').attr('href').replace(/[#]/g, '')
const postTitle = document.querySelector(`#cnblogs_post_body [id='${titleId}']`)
if (getClientRect(postTitle).top <= 10) {
if ($($('#catalog ul li')[i]).hasClass('catalog-active')) return
$($('#catalog ul li')[i]).addClass('catalog-active')
$($('#catalog ul li')[i]).siblings().removeClass('catalog-active')
return
}
}
},
50,
1000 / 60
)
)
}
项目链接
原文地址:https://www.cnblogs.com/guangzan/p/12669090.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 【C++简明教程】Python和C++指定元素排序比较
- 【深度学习】基于web端和C++的两种深度学习模型部署方式
- 作为DBA,你有必要了解一下tcpdump
- Linux用户管理
- 有赞 GO 项目单测、集成、增量覆盖率统计与分析
- RSA--通过模和指数加密模板--无填充
- 有赞发号器多机房方案
- python爬虫以及后端开发--实用加密模板整理
- APP脱壳方法三
- Flink Checkpoint 原理流程以及常见失败原因分析
- Docker原理之 - OverlayFS设计与实现
- 有赞零售跨平台打印库方案
- [Go] Golang练习项目-GO语言实现快速排序-第一个数作为基准更容易理解
- 有赞移动基础设施建设的实践和思考
- 大数据理论篇HDFS的基石——Google File System