joe文章目录侧边栏
效果如图:
实现代码
修改php文件
- 需要修改的文件:
/usr/themes/Joe/public/aside.php - 在
aside.php的合适位置增加如下代码,用于在侧边栏创建目录容器
# 仅在文章和页面生效
<?php if (($this->is('post') || $this->is('page')) : ?>
<section class="joe_aside__item catalogue">
<div class="joe_aside__item-title">
<svg class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2084" width="18" height="18"><path d="M640 192H224c-17.7 0-32-14.3-32-32s14.3-32 32-32h416c17.7 0 32 14.3 32 32s-14.3 32-32 32zM960 544H224c-17.7 0-32-14.3-32-32s14.3-32 32-32h736c17.7 0 32 14.3 32 32s-14.3 32-32 32zM640 896H224c-17.7 0-32-14.3-32-32s14.3-32 32-32h416c17.7 0 32 14.3 32 32s-14.3 32-32 32zM96 192H64c-17.7 0-32-14.3-32-32s14.3-32 32-32h32c17.7 0 32 14.3 32 32s-14.3 32-32 32zM96 544H64c-17.7 0-32-14.3-32-32s14.3-32 32-32h32c17.7 0 32 14.3 32 32s-14.3 32-32 32zM96 896H64c-17.7 0-32-14.3-32-32s14.3-32 32-32h32c17.7 0 32 14.3 32 32s-14.3 32-32 32z" p-id="2085"></path></svg>
<span class="text">目录</span>
<span class="line"></span>
</div>
<div class="joe_aside__item-contain">
<ul class="catalogue-items">
</ul>
</div>
</section>
<?php endif; ?>增加js代码
- 下面的js可以直接在Joe主题的设置中添加
- 位置: 控制台->外观->设置外观->全局设置->自定义js
function get_catalogs(article_content) {
const titleTag = ["H1", "H2", "H3"];
let titles = [];
article_content.childNodes.forEach((e, index) => {
const id = "header-" + index;
if(titleTag.includes(e.nodeName)){
titles.push({
id: id,
text: e.textContent,
level: Number(e.nodeName.substring(1, 2))
});
e.setAttribute("id", id);
}
});
return titles;
}
// 找到目录容器
article_content = document.querySelector('.joe_detail__article');
if (article_content) {
var catalog = get_catalogs(article_content);
if (catalog.length == 0) {
// 无目录,隐藏
$('.catalogue').hide();
} else {
let catalogue = '';
for (let i = 0; i < catalog.length; i++) {
let node = '<li class="catalogue-item"><a href="javascript:;" id="to-' + catalog[i].id + '" to="' + catalog[i].id + '" title="' + catalog[i].text + '">' + catalog[i].text + '</a>';
if (i == catalog.length - 1) {
catalogue += node + '</li>'
} else {
if (catalog[i + 1].level == catalog[i].level) {
catalogue += node + '</li>';
} else if (catalog[i + 1].level > catalog[i].level) {
catalogue += (catalog[i + 1].level > 1) ? node + '<ul class="level-' + catalog[i + 1].level + '">' : node + '</li>';
} else {
if (catalog[i + 1].level - catalog[i].level == -2) {
catalogue += i > 1 ? node + '</li></ul></li></ul></li>' : node + '</li></ul></li>';
} else {
catalogue += i > 1 ? node + '</li></ul></li>' : node + '</li>';
}
}
}
}
document.querySelector('.catalogue-items').innerHTML = catalogue;
$('.catalogue-item > a').on('mouseenter', function () {
$(this).parent().addClass('_active');
});
$('.catalogue-item > a').on('mouseleave', function () {
$(this).parent().removeClass('_active');
});
// 根据目录定位到标题
$('.catalogue-item > a').on('click', function () {
document.removeEventListener("scroll", autoActive);
$('.catalogue-item').removeClass('active');
$(this).parent().addClass('active');
let aim = document.querySelector('#' + $(this).attr('to'));
let aim_top = aim.offsetTop;
let aim_h = aim.clientHeight;
let above_h = document.querySelector('.joe_header__above').clientHeight;
let below_h = document.querySelector('.joe_header__below').clientHeight;
let offset = 0;
let case1 = !document.querySelector('.joe_header__above').className.includes('active');
let case2 = document.getElementsByTagName("html")[0].scrollTop + above_h > aim_top;
if (case1 && case2) {
offset = above_h;
}
window.scrollTo({
top: aim_top - offset - below_h - 10,
behavior: 'smooth'
});
setTimeout(() => {
document.addEventListener("scroll", autoActive);
}, 500);
});
if (catalog.length)
$('.catalogue-item').eq(0).addClass('active');
// 目录侧标题自动定位
let autoActive = function () {
let html_top = document.getElementsByTagName("html")[0].scrollTop; //获得父级卷去的高度
for (let i = 0; i < catalog.length; i++) {
let offset = 0;
let h_id = '#' + catalog[i].id;
let h_offset = document.querySelector(h_id).offsetTop;
let above_h = document.querySelector('.joe_header__above').clientHeight;
let below_h = document.querySelector('.joe_header__below').clientHeight;
if (!document.querySelector('.joe_header').className.includes('active'))
offset = above_h;
if (h_offset + below_h + offset + 10 >= html_top) {
$('.catalogue-item').removeClass('active');
if (i > 0 && i < catalog.length - 1 && document.querySelector('#' + catalog[i].id).offsetTop > html_top + window.innerHeight * 0.2) {
//还没到下一个标题
i--;
}
$('#to-' + catalog[i].id).parent().addClass('active');
break;
}
}
};
document.addEventListener("scroll", autoActive);
}
} else {
// 不是文章,隐藏目录
$('.catalogue').hide();
}css样式表
- 样式表同js,也可以在Joe主题的设置中添加
- 位置: 控制台->外观->设置外观->全局设置->自定义css
以下样式表是我自己博客使用的,仅供参考
.joe_aside__item.catalogue { z-index: 999; position: sticky; top: 45px; margin-bottom: 15px; transition: top 0.35s; background: var(--background) } .joe_aside__item.catalogue .joe_aside__item-contain { padding: 0; margin: 0; margin-left: 10px } .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items { border-left: 1px solid var(--classC); border-bottom: 1px solid var(--background); padding: 15px } .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item { margin: 0; padding: 0; line-height: 26px; font-size: 16px } .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item a { position: relative; display: block; line-height: 26px; color: var(--main); transition: color 0.5s } .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item a: hover { color: var(--theme) } .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item._active>a, .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item.active>a { color: var(--theme) } .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item._active>a::before, .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item.active>a::before { content: ""; position: absolute; left: -17px; top: 0; width: 2px; height: 26px; background-color: var(--theme); transition: height 0.35s } .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-2.catalogue-item, .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-3 .catalogue-item { font-size: 14px } .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-2 .catalogue-item._active>a::before, .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-2 .catalogue-item.active>a::before, .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-3 .catalogue-item._active>a::before, .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-3 .catalogue-item.active>a::before { left: -34px } .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-2 .catalogue-item .level-3 .catalogue-item, .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-3 .catalogue-item .level-3 .catalogue-item { font-size: 12px } .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-2 .catalogue-item .level-3 .catalogue-item._active>a::before, .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-2 .catalogue-item .level-3 .catalogue-item.active>a::before, .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-3 .catalogue-item .level-3 .catalogue-item._active>a::before, .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-3 .catalogue-item .level-3 .catalogue-item.active>a::before { left: -51px } .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item .level-3 .catalogue-item { font-size: 12px } .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items .catalogue-item ul { padding-left: 17px } .joe_aside__item.catalogue .joe_aside__item-contain .catalogue-items ul { display: block; list-style-type: disc }
二次修改 js代码
js代码
// 自定义文章目录侧边栏-start
function get_catalogs(article_content) {
const titleTag = ["H2", "H3", "H4"];
let titles = [];
article_content.childNodes.forEach((e, index) => {
const id = "header-" + index;
if(titleTag.includes(e.nodeName)){
titles.push({
id: id,
text: e.textContent,
level: Number(e.nodeName.substring(1, 2) - 1)
});
e.setAttribute("id", id);
}
});
return titles;
}
// 找到目录容器
article_content = document.querySelector('.joe_detail__article');
if (article_content) {
var catalog = get_catalogs(article_content);
console.log(catalog, '标题级别');
if (catalog.length == 0) {
// 无目录,隐藏
$('.catalogue').hide();
} else {
const arr = []
function getLv1(catalog, index, arr, lv, lv1Item) { // 获取一级菜单
// console.log(arr, '传递的arr / itemchildren”');
const newArr = JSON.parse(JSON.stringify(catalog)).slice(index) // 从哪个位置开始遍历
// console.log(newArr, '索引位置截取');
if (newArr.length === 0) return
// console.log(lv1Item, '一级');
// for循环可以进行 打破 终结循环
for(let i = 0; i < newArr.length; i++) {
newArr[i].children = []
if (newArr[i].level === lv) { // 拿到对应等级的 放到一起
newArr[i].el = `
<li class="catalogue-item">
<a
href="javascript:;"
id="to-${ newArr[i].id }"
to="${ newArr[i].id }"
title="${ newArr[i].text }"
>
${ newArr[i].text }
</a>
<ul class="level-${lv+1}">
cy_oo${newArr[i].id + i}
</ul>
</li>
`
newArr[i].replaceName = 'cy_oo' + newArr[i].id + i
arr.push(newArr[i])
// console.log(newArr[i], '当前item');
}
// console.log(arr, '123456');
// if (item.level !== 1 && item.level < catalog[i - 1].level) lv1.push(item)
// newArr[i + 1].level < newArr[i].level
// 没有下一个了
if(!newArr[i + 1]) return
// if (newArr[i + 1].level < newArr[i].level) continue
// 下个级别 = 1 遇到级别 为1 停止遍历
if (((newArr[i + 1].level === 1 || newArr[i + 1].level < lv) && lv !== 1)) return
// if (newArr[i].text === '示例') {
// console.log(newArr[i], '当前item1111');
// console.log(newArr[i], '上一个item1111');
// console.log(newArr[i + 1], '下一个item');
// }
// 从 索引 + 1 位置循环
// 判断下一级 是否大于 当前级别
if(newArr[i + 1].level > newArr[i].level) {
// console.log(i + 1, '下一级别索引');
// console.log(item, '当前item');
// console.log(item.children, '当前children', catalog[i + 1].level, '下一级级别');
let lv1ItemEl = lv1Item
if (lv === 1) {
lv1ItemEl = newArr[i]
}
getLv1(newArr, i + 1, newArr[i].children, newArr[i + 1].level, lv1ItemEl)
}
// ===
if (newArr[i + 1].level === newArr[i].level) {
// break;
}
}
}
getLv1(catalog, 0, arr, 1, null)
// console.log(arr, '最终');
// 拼接dom字符串
function getDomStr(obj, arr) {
// console.log(arr, 123456);
let liStr = ''
arr.forEach(li => {
liStr += li.el
})
// cy_oo + id
// console.log(obj.lv1Item.replaceName, '55555555555');
obj.domStr = obj.domStr.replace(obj.lv1Item.replaceName, liStr)
arr.forEach((item, i) => {
// console.log(obj, obj.domStr);
if (item.children && item.children.length) {
obj.lv1Item = item
getDomStr(obj, item.children)
} else {
// console.log(item, '999999999999999');
obj.domStr = obj.domStr.replace(item.replaceName, '')
}
})
// console.log(lv1Item.el.replace('cy_oo', 123456));
// console.log(domStr, 99999999999);
}
let catalogue = ''
arr.forEach(item => {
const lv1Item = item
let domStr = lv1Item.el
const obj = {
domStr,
lv1Item,
rStr: 'cy_oo',
newStr: ''
}
// if (item.children && item.children.length) {
// getDomStr(domStr, item.children)
// }
getDomStr(obj, lv1Item.children)
// if (item.text === '介绍') {
// console.log(obj.domStr, '9999999999999');
// }
// console.log(obj.domStr, '9999999999999');
catalogue+=obj.domStr
// console.log(domStr, '9999999999999');
})
// console.log(catalogue, 6666666666666);
// document.querySelector('.catalogue-items').innerHTML = catalogue;
document.querySelector('.catalogue-items').innerHTML = catalogue;
$('.catalogue-item > a').on('mouseenter', function () {
$(this).parent().addClass('_active');
});
$('.catalogue-item > a').on('mouseleave', function () {
$(this).parent().removeClass('_active');
});
// 根据目录定位到标题
$('.catalogue-item > a').on('click', function () {
document.removeEventListener("scroll", autoActive);
$('.catalogue-item').removeClass('active');
$(this).parent().addClass('active');
let aim = document.querySelector('#' + $(this).attr('to'));
let aim_top = aim.offsetTop;
let aim_h = aim.clientHeight;
let above_h = document.querySelector('.joe_header__above').clientHeight;
let below_h = document.querySelector('.joe_header__below').clientHeight;
let offset = 0;
let case1 = !document.querySelector('.joe_header__above').className.includes('active');
let case2 = document.getElementsByTagName("html")[0].scrollTop + above_h > aim_top;
// console.log(case1, case2);
// if (case1 && case2) {
// offset = above_h;
// }
window.scrollTo({
top: aim_top - offset - above_h - below_h - 10,
behavior: 'smooth'
});
setTimeout(() => {
document.addEventListener("scroll", autoActive);
}, 500);
});
if (catalog.length)
$('.catalogue-item').eq(0).addClass('active');
// 目录侧标题自动定位
let autoActive = function () {
let html_top = document.getElementsByTagName("html")[0].scrollTop; //获得父级卷去的高度
for (let i = 0; i < catalog.length; i++) {
let offset = 0;
let h_id = '#' + catalog[i].id;
let h_offset = document.querySelector(h_id).offsetTop;
let above_h = document.querySelector('.joe_header__above').clientHeight;
let below_h = document.querySelector('.joe_header__below').clientHeight;
if (!document.querySelector('.joe_header').className.includes('active'))
offset = above_h;
if (h_offset + below_h + offset + 10 >= html_top) {
$('.catalogue-item').removeClass('active');
if (i > 0 && i < catalog.length - 1 && document.querySelector('#' + catalog[i].id).offsetTop > html_top + window.innerHeight * 0.2) {
//还没到下一个标题
i--;
}
$('#to-' + catalog[i].id).parent().addClass('active');
break;
}
}
};
document.addEventListener("scroll", autoActive);
}
} else {
// 不是文章,隐藏目录
$('.catalogue').hide();
}
// 自定义文章目录侧边栏-end本文内容参考:开发者社区-苏苏
[...]源代码里的直接改动joe主题备份的修复原joe主题备份点击没有反应备份不了,用了一个其他主题的备份代码替换joe主题的备份代码之后实现了成功备份,并且能正常还原备份,文件路径 Joe-master/core/backup.php文章页面本来文章下方有个转载协议,觉得没必要就改成了分享提示语,并且改成点击分享那句话变成分享到qq空间,同时改了本文链接的显示,改成显示为文章标题并且点击标题自动复制本文[...]
aside这里的代码有问题吗?直接复制的弄好后出错。提示这个 syntax error, unexpected ':'开始以为是不是弄错了,又重新复制了几次,结果还是一样的
$前面少一个(,下面是改过的版本
这个是原版
aside.php
第一个 #注释,不要粘贴上去.....
应该没有吧,我用的就是这个,
$前面少一个(,下面是改过的版本
这个是原版
是这样的,不仔细看,都注意不到