自动生成侧边栏

This commit is contained in:
xugaoyi 2019-12-24 17:27:37 +08:00
parent 9af64dc50f
commit e47e5aa8b5
43 changed files with 687 additions and 140 deletions

View File

@ -1,11 +1,12 @@
name: CI
#on: [push]
# 在master分支发生push事件时触发。
on:
push:
branches:
- master
# on:
# push:
# branches:
# - master
jobs: # 工作流
build: # 自定义名称

View File

@ -1,5 +1,7 @@
const nav = require('./config/nav.js');
const sidebar = require('./config/sidebar.js');
// const sidebar = require('./config/sidebar.js');
const sidebar = require('./config/sidebar-auto.js');
module.exports = {
title: 'Evan Blog', // 标题
description: 'Evan Blog,web前端技术博客,基于vuepress构建,专注web前端学习与总结。JavaScript,js,ES6,TypeScript,vue,python,css3,html5,Node,git,github等技术文章。', // 描述,以 <meta> 标签渲染到当前页面的 HTML 中

View File

@ -1,44 +1,43 @@
module.exports = [
{text: '首页', link: '/'},
{
text: '前端',
{text: '前端', link: '/01.前端/01.JavaScript/01.JavaScript中的名词概念'},
{text: '页面', link: '/02.页面/01.html-css/00.flex布局语法'},
{text: '技术杂谈', link: '/03.技术杂谈/01.技术杂谈/01.Git使用手册'},
{text: '其他',
items: [
{text: 'JavaScript', link: '/web/JavaScript/01.JavaScript中的名词概念'},
//{text: 'vue', link: '/web/vue/'},
//{text: 'TypeScript', link: '/web/TypeScript/'},
//{text: 'ES6', link: '/web/ES6/'},
{text: '学习', link: '/04.其他/01.学习/01.学习网站'},
{text: '学习笔记', link: '/04.其他/02.学习笔记/01.小程序笔记'},
{text: '面试', link: '/04.其他/03.面试/01.面试问题集锦'},
{text: '在线工具', link: '/04.其他/04.在线工具'},
{text: '友情链接', link: '/04.其他/05.友情链接'},
]
},
{
text: '页面',
items: [
{text: 'HTML/CSS', link: '/ui/00.flex布局语法'},
]
},
{text: '技术杂谈',items:[
{text: '技术',items:[
{text: 'Git使用文档', link: '/other/git'},
{text: 'GitHub高级搜索技巧', link: '/other/github'},
{text: 'Markdown使用教程', link: '/other/markdown'},
{text: 'npm使用教程', link: '/other/npm'},
{text: 'yaml教程', link: '/other/yaml'},
]},
{text: '学习',items:[
{text: '学习效果低,忘性很大怎么办?',link: '/other/LearningAndMemory'},
{text: '学习网站分享', link: '/other/study'},
]},
{text: '学习笔记',items:[
{text: '小程序笔记',link: '/other/note/01.小程序笔记'},
{text: '《Python语言程序设计》基础课程学习',link: 'https://github.com/xugaoyi/python-learn'},
]},
{text: '面试',items:[
{text: '面试问答集锦', link: '/other/interview'},
]},
{text: '其他',items:[
{text: '在线工具', link: '/other/utils'},
{text: '关于本博客搭建', link: 'https://github.com/xugaoyi/evanblog'},
{text: '解决百度无法收录搭建在GitHub上的个人博客的问题', link: '/other/baidushoulu'}
]},
]},
{text: '关于我',link: '/about/'}
{text: '关于我', link: '/05.关于我/01.关于我'},
// {text: '技术杂谈',items:[
// {text: '技术',items:[
// {text: 'Git使用文档', link: '/other/git'},
// {text: 'GitHub高级搜索技巧', link: '/other/github'},
// {text: 'Markdown使用教程', link: '/other/markdown'},
// {text: 'npm使用教程', link: '/other/npm'},
// {text: 'yaml教程', link: '/other/yaml'},
// ]},
// {text: '学习',items:[
// {text: '学习效果低,忘性很大怎么办?',link: '/other/LearningAndMemory'},
// {text: '学习网站分享', link: '/other/study'},
// ]},
// {text: '学习笔记',items:[
// {text: '小程序笔记',link: '/other/note/01.小程序笔记'},
// {text: '《Python语言程序设计》基础课程学习',link: 'https://github.com/xugaoyi/python-learn'},
// ]},
// {text: '面试',items:[
// {text: '面试问答集锦', link: '/other/interview'},
// ]},
// {text: '其他',items:[
// {text: '在线工具', link: '/other/utils'},
// {text: '关于本博客搭建', link: 'https://github.com/xugaoyi/evanblog'},
// {text: '解决百度无法收录搭建在GitHub上的个人博客的问题', link: '/other/baidushoulu'}
// ]},
// ]},
]

View File

@ -0,0 +1,15 @@
// 侧边栏自动生成
module.exports = {
"/01.前端/": [{"title":"JavaScript","collapsable":false,"children":[["01.JavaScript/01.JavaScript中的名词概念.md","JavaScript中的名词概念"],["01.JavaScript/02.数据类型转换.md","数据类型转换"],["01.JavaScript/03.ES5面向对象.md","ES5面向对象"],["01.JavaScript/04.ES6面向对象.md","ES6面向对象"],["01.JavaScript/05.new命令原理.md","new命令原理"],["01.JavaScript/06.多种数组去重性能对比.md","多种数组去重性能对比"]]}],
"/02.页面/": [{"title":"html-css","collapsable":false,"children":[["01.html-css/00.flex布局语法.md","flex布局语法"],["01.html-css/01.flex布局案例-基础.md","flex布局案例-基础"],["01.html-css/02.flex布局案例-骰子.md","flex布局案例-骰子"],["01.html-css/03.flex布局案例-网格布局.md","flex布局案例-网格布局"],["01.html-css/04.flex布局案例-圣杯布局.md","flex布局案例-圣杯布局"],["01.html-css/05.flex布局案例-输入框布局.md","flex布局案例-输入框布局"],["01.html-css/06.CSS3之transform过渡.md","CSS3之transform过渡"],["01.html-css/07.CSS3之animation动画.md","CSS3之animation动画"]]}],
"/03.技术杂谈/": [{"title":"技术杂谈","collapsable":false,"children":[["01.技术杂谈/01.Git使用手册.md","Git使用手册"],["01.技术杂谈/02.GitHub高级搜索技巧.md","GitHub高级搜索技巧"],["01.技术杂谈/03.Markdown使用教程.md","Markdown使用教程"],["01.技术杂谈/04.npm常用命令.md","npm常用命令"],["01.技术杂谈/05.yaml语言教程.md","yaml语言教程"],["01.技术杂谈/06.解决百度无法收录搭建在GitHub上的个人博客的问题.md","解决百度无法收录搭建在GitHub上的个人博客的问题"],["01.技术杂谈/07.使用Gitalk实现静态博客无后台评论系统.md","使用Gitalk实现静态博客无后台评论系统"]]}],
"/04.其他/": [{"title":"学习","collapsable":false,"children":[["01.学习/01.学习网站.md","学习网站"],["01.学习/02.学习效率低,忘性很大怎么办?.md","学习效率低,忘性很大怎么办?"]]},{"title":"学习笔记","collapsable":false,"children":[["02.学习笔记/01.小程序笔记.md","小程序笔记"]]},{"title":"面试","collapsable":false,"children":[["03.面试/01.面试问题集锦.md","面试问题集锦"]]},["04.在线工具.md","在线工具"],["05.友情链接.md","友情链接"]],
"/05.关于我/": [["01.关于我.md","关于我"]],
}

View File

@ -1,79 +1,75 @@
module.exports = { // 侧边栏
'/web/': [
'/01.前端/': [
{
title: 'JavaScript',
collapsable: false, //是否可折叠可选的默认true
children: [
['JavaScript/01.JavaScript中的名词概念','JavaScript中的名词概念'],
['JavaScript/02.数据类型转换','数据类型转换'],
['JavaScript/03.ES5面向对象','ES5面向对象'],
['JavaScript/04.ES6面向对象','ES6面向对象'],
['JavaScript/05.new命令原理','new命令原理'],
['JavaScript/06.多种数组去重性能对比','多种数组去重性能对比'],
['01.JavaScript/01.JavaScript中的名词概念','JavaScript中的名词概念'],
['01.JavaScript/02.数据类型转换','数据类型转换'],
['01.JavaScript/03.ES5面向对象','ES5面向对象'],
['01.JavaScript/04.ES6面向对象','ES6面向对象'],
['01.JavaScript/05.new命令原理','new命令原理'],
['01.JavaScript/06.多种数组去重性能对比','多种数组去重性能对比'],
]
},
],
'/ui/': [
'/02.页面/': [
{
title: 'HTML/CSS',
title: 'html-css',
collapsable: false,
children: [
['00.flex布局语法','flex布局语法'],
['01.flex布局案例-基础','flex布局案例-基础'],
['02.flex布局案例-骰子','flex布局案例-骰子'],
['03.flex布局案例-网格布局','flex布局案例-网格布局'],
['04.flex布局案例-圣杯布局','flex布局案例-圣杯布局'],
['05.flex布局案例-输入框布局','flex布局案例-输入框布局'],
['06.CSS3之transform过渡','CSS3之transform过渡'],
['07.CSS3之animation动画','CSS3之animation动画'],
['01.html-css/00.flex布局语法','flex布局语法'],
['01.html-css/01.flex布局案例-基础','flex布局案例-基础'],
['01.html-css/02.flex布局案例-骰子','flex布局案例-骰子'],
['01.html-css/03.flex布局案例-网格布局','flex布局案例-网格布局'],
['01.html-css/04.flex布局案例-圣杯布局','flex布局案例-圣杯布局'],
['01.html-css/05.flex布局案例-输入框布局','flex布局案例-输入框布局'],
['01.html-css/06.CSS3之transform过渡','CSS3之transform过渡'],
['01.html-css/07.CSS3之animation动画','CSS3之animation动画'],
]
},
],
'/other/': [
'/03.技术杂谈/': [
{
title: '技术',
title: '技术杂谈',
collapsable: false, //是否可折叠可选的默认true
sidebarDepth: 2, // 深度,可选的, 默认值是 1
children: [
['git','Git使用文档'], // 同 {title: 'Git使用文档',path: 'git'}
['github','GitHub高级搜索技巧'],
['markdown','Markdown使用教程'],
['npm','npm使用教程'],
['yaml','yaml教程'],
['01.Git使用手册','Git使用手册'], // 同 {title: 'Git使用文档',path: 'git'}
['02.GitHub高级搜索技巧','GitHub高级搜索技巧'],
['03.Markdown使用教程','Markdown使用教程'],
['04.npm常用命令','npm常用命令'],
['05.yaml语言教程','yaml语言教程'],
['06.解决百度无法收录搭建在GitHub上的个人博客的问题','解决百度无法收录搭建在GitHub上的个人博客的问题'],
['07.使用Gitalk实现静态博客无后台评论系统','使用Gitalk实现静态博客无后台评论系统'],
]
},
}
],
'/04.其他/': [
{
title: '学习',
collapsable: false,
children: [
['LearningAndMemory','学习效果低,忘性很大怎么办?'],
['study','学习网站分享'],
['01.学习/01.学习网站','学习网站'],
['01.学习/02.学习效率低,忘性很大怎么办?','学习效率低,忘性很大怎么办?'],
]
},
{
title: '学习笔记',
collapsable: false,
children: [
['note/01.小程序笔记','小程序笔记'],
['https://github.com/xugaoyi/python-learn','《Python语言程序设计》基础课程学习'],
['02.学习笔记/01.小程序笔记','小程序笔记'],
]
},
{
title: '面试',
collapsable: false,
collapsable: false, //是否可折叠可选的默认true
children: [
['interview','面试问题集锦'],
]
},
{
title: '其他',
collapsable: false,
children: [
['utils','在线工具'],
['https://github.com/xugaoyi/evanblog','关于本博客搭建'],
['baidushoulu','解决百度无法收录搭建在GitHub上的个人博客的问题']
['03.面试/01.面试问题集锦','面试问题集锦'],
]
},
['01.在线工具','在线工具'],
['02.友情链接','友情链接'],
],
// '/': [ // 在最后定义,在没有单独设置侧边栏时统一使用这个侧边栏
// '',

View File

@ -1,3 +1,8 @@
<!-- ---
title: 我是javascript
permalink: /javascript
--- -->
# JavaScript中的名词概念
## 什么是作用域?

View File

@ -1,6 +1,6 @@
# Git使用文档
# Git使用手册
## 安装

View File

@ -4,7 +4,7 @@
### 简介
<img src='./md-img/logo.png' width='120px' style='float:left'>
![logo](https://raw.githubusercontent.com/xugaoyi/image_store/master/blog/md_logo.png)
`Markdown` 是一种轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档。
@ -45,7 +45,7 @@
徽章生成网站:<https://shields.io/>
本文档主要介绍markdown不对徽章做过多介绍详细介绍请 [ 戳我 ](https://segmentfault.com/a/1190000019552597) 访问
本文档主要介绍markdown不对徽章做过多介绍详细介绍请 [ 戳我 ](https://segmentfault.com/a/1190000019552597) 了解
@ -663,32 +663,6 @@ function test() {
## 十、图片
```
语法:
![alt替代文本](图片地址)
![alt替代文本](图片地址 "title标题")
```
- 开头一个感叹号 !
- 接着一个方括号,里面放上图片的替代文字
- 接着一个普通括号,里面放上图片的地址,最后还可以用引号包住并加上选择性的 'title' 属性的文字。
```
语法:
![logo](./md-img/logo.png "logo")
```
![logo](./md-img/logo.png "logo")
当然,你也可以像链接那样对图片地址使用变量:
@ -698,33 +672,33 @@ function test() {
然后在文档的结尾或其他位置给变量赋值(图片地址)
语法:
![RUNOOB][img]
[img]: ./md-img/logo.png
[img]: https://raw.githubusercontent.com/xugaoyi/image_store/master/blog/md_logo.png
```
![RUNOOB][img]
[img]: ./md-img/logo.png
[img]: https://raw.githubusercontent.com/xugaoyi/image_store/master/blog/md_logo.png
### 图片宽高
如下想设置图片宽高,可以使用 <img> 标签。
如下想设置图片宽高,可以使用 `<img>` 标签。
```
语法:
<img src="./md-img/logo.png" width="50px" height="30px">
<img src="https://raw.githubusercontent.com/xugaoyi/image_store/master/blog/md_logo.png" width="50px" height="30px">
```
<img src="./md-img/logo.png" width="50px" height="30px">
<img src="https://raw.githubusercontent.com/xugaoyi/image_store/master/blog/md_logo.png" width="50px" height="30px">
### 相对路径以及Github中使用图片
不管是在本地还是在github同一个仓库中如果图片存在可以使用**相对路径**。github上如果引用其他github仓库中的图片则要注意地址格式`仓库地址/raw/分支名/图片路径`
不管是在本地还是在github同一个仓库中如果图片存在可以使用**相对路径**。
相对路径图片:
@ -733,15 +707,14 @@ function test() {
![头像图片](./md-img/test.jpg)
```
![头像图片](./md-img/test.jpg)
其他仓库的图片:
github上如果引用其他github仓库中的图片则要注意地址格式`仓库地址/raw/分支名/图片路径` 或 `https://raw.githubusercontent.com/用户名/仓库名/分支名/图片路径`
```
语法:
![其他仓库的图片](https://github.com/xugaoyi/vue-music/raw/master/src/common/image/default.png)
![其他仓库的图片1](https://github.com/xugaoyi/vue-music/raw/master/src/common/image/default.png)
![其他仓库的图片2](https://raw.githubusercontent.com/xugaoyi/image_store/master/blog/md_logo.png)
```
@ -750,7 +723,7 @@ function test() {
![其他仓库的图片2](https://raw.githubusercontent.com/xugaoyi/image_store/master/blog/md_logo.png)
## 十一、表格

View File

@ -1,4 +1,4 @@
# npm使用教程
# npm常用命令
## 简介

View File

@ -1,4 +1,4 @@
# yaml教程
# yaml语言教程
## 简介

View File

@ -1,4 +1,4 @@
# 解决百度无法收录搭建在GitHub上的个人博客的问题
# 解决百度无法收录搭建在GitHub上的静态博客的问题

View File

@ -0,0 +1,211 @@
# 使用Gitalk实现静态博客无后台评论系统
## 前言
想在vuepress搭建的静态博客中添加一个评论功能发现Gitalk是一个不错的选择。
Gitalk一个基于 Github Issue 和 Preact 开发的评论插件。
下面我们就来实现它吧~
## 准备
使用一个新的东西首先当然是要了解它啦
Gitalk demo<https://gitalk.github.io/>
Gitalk github<https://github.com/gitalk/gitalk>
## 实现
如何实现?最好的方法我认为是看[官方文档](https://github.com/gitalk/gitalk/blob/master/readme-cn.md),这里我只是记录一下实现的步骤。
使用一个别人已经开发好的 [vuepress-plugin-comment](https://github.com/dongyuanxin/vuepress-plugin-comment) 插件来帮助我们把Gitalk应用到vuepress搭建的静态博客。
### 安装
```sh
npm install --save vuepress-plugin-comment
```
### 使用
`options`的配置和`Gitalk`的配置相同
```js
module.exports = {
plugins: [
[
'vuepress-plugin-comment',
{
choosen: 'gitalk',
options: {
clientID: 'GitHub Application Client ID',
clientSecret: 'GitHub Application Client Secret',
repo: 'GitHub repo',
owner: 'GitHub repo owner',
admin: ['GitHub repo owner and collaborators, only these guys can initialize github issues'],
distractionFreeMode: false
}
}
]
]
}
```
需要 **GitHub Application**,如果没有 [点击这里申请](https://github.com/settings/applications/new)`Authorization callback URL` 填写当前使用插件页面的域名。
![](https://raw.githubusercontent.com/xugaoyi/image_store/master/blog/QQ%E6%88%AA%E5%9B%BE20191220124134.jpg)
申请完成就会得 Client ID 和 Client Secret。然后把对应参数填写到配置中
```js
module.exports = {
plugins: [
[
'vuepress-plugin-comment',
{
choosen: 'gitalk',
options: {
clientID: 'a6e*******4709b88b',
clientSecret: 'f0e***************beb8b2d54d7241',
repo: 'blog', // GitHub 仓库
owner: 'xugaoyi', // GitHub仓库所有者
admin: ['xugaoyi'], // 对仓库有写权限的人
distractionFreeMode: false
}
}
]
]
}
```
配置好之后重启项目就发现页面上多了一个评论区说明评论功能实现啦。但还是有一些bug继续完善它~
### BUG修复
**评论区与博客样式不匹配**
解决办法:新增全局样式文件`.vuepress/styles/index.styl`,写入样式
```stylus
#vuepress-plugin-comment
max-width $contentWidth
margin 0 auto
padding 2rem 2.5rem
@media (max-width: $MQNarrow)
padding 2rem
@media (max-width: $MQMobileNarrow)
padding 1.5rem
```
**评论区出现 Error: Validation Failed.**
问题分析:当页面 链接过长 或 存在中文链接导致整个链接字符串长度超过50时会造成请求issues接口失败出现422状态码。中文链接会自动转码变得很长id参数默认取的是链接长度不能超过50
解决办法手动设置id取值限制长度不超过50。
```js
{
choosen: 'gitalk',
options: {
...
id: "<%- (window.location.origin + (frontmatter.to.path || window.location.pathname)).slice(-50) %>", // 页面的唯一标识,长度不能超过50
title: "「评论」<%- document.title %>", // GitHub issue 的标题
labels: ["Gitalk", "Comment"], // GitHub issue 的标签
body:"<%- document.title %><%- window.location.origin + (frontmatter.to.path || window.location.pathname) %>" // GitHub issue 的内容
}
}
```
> 访问变量时,如 `$frontmatter``window`等,请使用 **EJS** 语法。因为在配置中不能使用回调函数会被vuepress过滤因此使用 **EJS** 语法。 ——插件作者文档说明
>
> **安装EJS**
>
> ```sh
> npm i ejs
> ```
**切换页面后评论区内容还是上一个页面的评论**
解决id在获取`path`时使用 `frontmatter.to.path`,插件内置了 ``frontmatter.from`、`frontmatter.to`。
```js
{
choosen: 'gitalk',
options: {
...
id: "<%- (window.location.origin + (frontmatter.to.path || window.location.pathname)).slice(-50) %>", // 页面的唯一标识,长度不能超过50
title: "「评论」<%- document.title %>", // GitHub issue 的标题
labels: ["Gitalk", "Comment"], // GitHub issue 的标签
body:"<%- document.title %><%- window.location.origin + (frontmatter.to.path || window.location.pathname) %>" // GitHub issue 的内容
}
}
```

View File

@ -1,4 +1,4 @@
# 学习网站分享
# 学习网站
## 文档类

View File

@ -1,4 +1,4 @@
# 学习效低,忘性很大怎么办?
# 学习效低,忘性很大怎么办?
## 关于学习

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

View File

@ -1,2 +0,0 @@
# test

View File

@ -1 +0,0 @@
> 敬请期待

View File

@ -1 +0,0 @@
> 敬请期待

View File

@ -1 +0,0 @@
> 敬请期待

View File

@ -2,9 +2,8 @@
"name": "evanblog",
"version": "1.0.0",
"scripts": {
"dev": "vuepress dev docs",
"list": "node utils/getFilenames.js",
"build": "vuepress build docs",
"dev": "node utils/sidebarAndNav.js && vuepress dev docs",
"build": "node utils/sidebarAndNav.js && vuepress build docs",
"deploy": "bash deploy.sh"
},
"license": "MIT",
@ -12,6 +11,7 @@
"@vuepress/plugin-back-to-top": "^1.2.0",
"@vuepress/plugin-medium-zoom": "^1.2.0",
"ejs": "^3.0.1",
"tracer": "^1.0.1",
"vuepress": "^1.1.0",
"vuepress-plugin-baidu-autopush": "^1.0.1",
"vuepress-plugin-baidu-tongji": "^1.0.1"

99
utils/permalink.js Normal file
View File

@ -0,0 +1,99 @@
/**
* nodejs自动生成永久链接
*/
const fs = require('fs'); // 文件模块
const path = require('path'); // 路径模块
const logger = require('tracer').colorConsole(); // 控制台工具(用于控制台打印信息包含时间、打印类型、文件及代码行号、对象、颜色)
const docsRoot = path.join(__dirname, '..', 'docs'); // docs文件路径
// 读取所有文件
function readFileList(dir, filesList = []) {
const files = fs.readdirSync(dir);
files.forEach((item, index) => {
var fullPath = path.join(dir, item);
const stat = fs.statSync(fullPath);
if (stat.isDirectory() && item !== '.vuepress') {
readFileList(path.join(dir, item), filesList); //递归读取文件
} else {
filesList.push(fullPath);
}
});
return filesList;
}
let filesList = readFileList(docsRoot);
console.log(filesList);
// main();
// /**
// * 主体函数
// */
// function main() {
// const tocs = readTocs(docsRoot); // 得到一个对路路径目录数组
// tocs.forEach(toc => { // toc为每个目录的绝对路径
// // console.log(toc)
// // E:\Github仓库集合\vuepress-Evan-blog\docs\01.前端
// // E:\Github仓库集合\vuepress-Evan-blog\docs\02.页面
// // E:\Github仓库集合\vuepress-Evan-blog\docs\03.技术杂谈
// // E:\Github仓库集合\vuepress-Evan-blog\docs\04.其他
// // E:\Github仓库集合\vuepress-Evan-blog\docs\05.关于我
// const files = fs.readdirSync(toc); // 读取目录(文件和文件夹),返回数组
// console.log(files)
// let [order, title, type] = filename.split('.');
// files.forEach(filename => {
// const file = path.resolve(toc, filename); // 方法:将路径或路径片段的序列解析为绝对路径
// const stat = fs.statSync(file); // 文件信息
// // console.log(file)
// if(stat.isDirectory()){ // 是否为文件夹目录
// } else {
// }
// })
// })
// }
/**
* 读取指定目录下的文件绝对路径
* @param {String} root 指定的目录
*/
function readTocs(root){
const result = [];
const files = fs.readdirSync(root); // 方法:读取目录,返回数组成员是root底下所有的目录名 (包含文件文件夹和文件)
files.forEach(name => {
const file = path.resolve(root, name); // 方法:将路径或路径片段的序列解析为绝对路径
if (fs.statSync(file).isDirectory() && name !== '.vuepress') { // 是否为文件夹目录,并排除.vuepress文件
result.push(file);
}
})
return result;
}

251
utils/sidebarAndNav.js Normal file
View File

@ -0,0 +1,251 @@
/**
* nodejs自动生成侧边栏与导航栏
*/
const fs = require('fs'); // 文件模块
const path = require('path'); // 路径模块
const ejs = require('ejs'); // ejs模板引擎
const logger = require('tracer').colorConsole(); // 控制台工具(用于控制台打印信息包含时间、打印类型、文件及代码行号、对象、颜色)
const docsRoot = path.join(__dirname, '..', 'docs'); // docs文件路径
const sidebarPath = path.join(__dirname, '..', 'docs', '.vuepress', 'config', 'sidebar-auto.js'); // 侧边栏js文件要保存的路径
const navPath = path.join(__dirname, '..', 'docs', '.vuepress', 'config', 'nav-auto.js'); // 导航栏js文件要保存的路径
// sidebar-auto.js代码模板
const sidebarTemplate = `
// 侧边栏自动生成
module.exports = {
<% for (let item of sidebarData) { %>
"<%- item.path %>": <%- JSON.stringify(item.sidebarArr) %>,
<% } %>
}`;
// nav-auto.js代码模板
const navTemplate = `
// 导航栏自动生成
module.exports = {
{text: '首页', link: '/'},
<% for (let item of navData) { %>
{
text: '<%- item.name %>',
<% if (item.navArr) {%>
items: [
<% for (let i of item.xx) { %>
{text: '<%- i.name %>', link: <%- i.link %>},
<% } %>
]
<% } else { %>
link: <%- item.link %>
<% } %>
},
<% } %>
}`;
main();
/**
* 主体函数
*/
function main() {
const sidebarData = [];
const navData = [];
const tocs = readTocs(docsRoot); // 得到一个对路路径目录数组
tocs.forEach(toc => { // toc为每个目录的绝对路径
const sidebarArr = mapTocToSidebar(toc);
//const navArr = mapTocToNav(toc);
//console.log(navArr)
if (!sidebarArr.length) {
logger.warn(`该目录 "${toc}" 内部没有任何文件,将忽略生成对应侧边栏`);
return;
}
sidebarData.push({
path: `/${path.basename(toc)}/`, // basename返回绝对路径的文件名
// name: path.basename(toc).replace(/ /g, '_'), // 替换空格
sidebarArr
})
})
const sidebarDataTem = ejs.render(sidebarTemplate, { sidebarData });
fs.writeFileSync(sidebarPath, sidebarDataTem); // 同步写入文件, 参数一:写入到的文件, 参数二:写入的数据
logger.info('侧边栏生成成功!')
}
/**
* 读取指定目录下的文件绝对路径
* @param {String} root 指定的目录
*/
function readTocs(root){
const result = [];
const files = fs.readdirSync(root); // 方法:读取目录,返回数组成员是root底下所有的目录名 (包含文件文件夹和文件)
files.forEach(name => {
const file = path.resolve(root, name); // 方法:将路径或路径片段的序列解析为绝对路径
if (fs.statSync(file).isDirectory() && name !== '.vuepress') { // 是否为文件夹目录,并排除.vuepress文件
result.push(file);
}
})
return result;
}
/**
* 将对应目录映射为对应的侧边栏配置
* @param {String} root
* @param {String} prefix
*/
function mapTocToSidebar(root, prefix){
prefix = prefix || '';
let sidebar = [];
const files = fs.readdirSync(root); // 读取目录(文件和文件夹),返回数组
files.forEach(filename => {
const file = path.resolve(root, filename); // 方法:将路径或路径片段的序列解析为绝对路径
const stat = fs.statSync(file); // 文件信息
let [order, title, type] = filename.split('.');
order = parseInt(order, 10);
if (isNaN(order) || order < 0) {
logger.error(`该文件 "${file}" 序号出错请填写正确的序号序号约定请查看https://github.com/xugaoyi/blog`);
return;
}
if (sidebar[order]) { // sidebar数组的order位置的数据的布尔值
logger.warn(`该文件 "${file}" 的序号在同一级别中有重复出现,将会被覆盖`);
}
if(stat.isDirectory()){ // 是否为文件夹目录
sidebar[order] = {
title,
collapsable: false,
children: mapTocToSidebar(file, prefix + filename + '/') // 子栏路径添加前缀
}
} else { // 是文件
if (type !== 'md') {
// 控制台错误信息
logger.error(`该文件 "${file}" 非md文件不支持非md文件类型`);
return;
}
sidebar[order] = [prefix + filename, title]; // [<前缀加完整文件名>, <文件标题>]
}
})
sidebar = sidebar.filter(item => item !== null && item !== undefined);
return sidebar;
}
/**
* 将对应目录映射导航
* @param {String} root
*/
function mapTocToNav(root){
let nav = [];
const prefix = path.basename(root); // basename返回绝对路径的文件名
let [order , text] = prefix.split('.');
order = parseInt(order, 10);
if (nav[order]) {
logger.warn(
`该序号 "${order}" 在同一级别中有重复出现,将会被覆盖`
);
}
const files = fs.readdirSync(root); // 方法:读取目录,返回数组
if (files.length === 1) { // 只有一级导航
let link = ''
const file = path.resolve(root, files[0]); // 方法:将路径或路径片段的序列解析为绝对路径
const stat = fs.statSync(file); // 文件信息
if (stat.isDirectory()) { // 文件夹
const files2 = fs.readdirSync(file);
if (!files2.length) {
logger.warn(`该目录 "${file}" 内部没有任何文件,将忽略生成对应导航`);
return;
}
link = `/${prefix}/${files}/${files2[0]}`
} else { // 文件
const type = files[0].split('.')[2];
if( type === 'md'){
link = `/${prefix}/${files}`
} else if (type === 'txt') { // 外部链接
} else { // 非md、txt文件
logger.error(`该文件 "${file}" 非md或txt文件不支持该文件类型`);
}
}
nav[order] = {
text,
link
}
} else if (files.length > 1) { // 二级导航
nav[order] = {
text,
items: twoNav(files,)
}
} else {
logger.warn(`该目录 "${root}" 内部没有任何文件,将忽略生成对应导航`);
}
return nav;
}
// 获取二级导航数据
function twoNav(files){
var items = [];
files.forEach(file => {
console.log(file)
let [order, text, type] = file.split('.');
order = parseInt(order, 10);
if (items[order]) {
logger.warn(
`该序号 "${order}" 在同一级别中有重复出现,将会被覆盖`
);
}
if (type === 'md') {
items[order] = {
text,
link: '/04.其他/01.学习/01.学习网站'
}
} else if (type === 'txt') { // 外部链接文件
} else if (type === undefined) { // 文件夹
items[order] = {
text,
link: '/04.其他/01.学习/01.学习网站'
}
} else { // 其他文件
logger.error(`该文件 "${file}" 非md或txt文件不支持该文件类型`);
}
})
// files.forEach(file => {
// const file2 = path.resolve(root, file); // 方法:将路径或路径片段的序列解析为绝对路径
// const stat = fs.statSync(file2); // 文件信息
// if (stat.isDirectory()) { // 文件夹
// console.log(mapTocToNav(path.resolve(root, file)))
// } else {
// }
// })
// items: [
// {text: '学习', link: '/04.其他/01.学习/01.学习网站'},
// {text: '学习笔记', link: '/04.其他/02.学习笔记/01.小程序笔记'},
// {text: '面试', link: '/04.其他/03.面试/01.面试问题集锦'},
// {text: '在线工具', link: '/04.其他/04.在线工具'},
// {text: '友情链接', link: '/04.其他/05.友情链接'},
// ]
return items;
}