从零开始创建一个简单博客
# 创建简单VuePress应用
- 创建并进入一个新目录
mkdir vuepress-starter && cd vuepress-starter
- 使用你喜欢的包管理器进行初始化
yarn init # npm init
- 将VuePress安装为本地依赖 作者已经不再推荐全局安装VuePress
yarn add -D vuepress # npm install -D vuepress
注意
如果你的现有项目依赖了 webpack 3.x,我们推荐使用 Yarn (opens new window) 而不是 npm 来安装 VuePress。因为在这种情形下,npm 会生成错误的依赖树。
- 创建你的第一篇文档
mkdir docs && echo '# Hello VuePress' > docs/README.md
5.在package.json
中添加一些scripts
这一步骤是可选的,但我们推荐你完成它。在下文中,我们会默认这些 scripts 已经被添加。
{
"scripts":{
"dev":"vuepress dev docs",
"docs:build":"vuepress build docs"
}
}
2
3
4
5
6
- 在本地启动服务器
yarn dev # npm run dev
VuePress 会在 http://localhost:8080 (opens new window) 启动一个热重载的开发服务器。
# 目录结构
VuePress 遵循 “约定优于配置” 的原则,推荐的目录结构如下:
├── docs
│ ├── .vuepress (可选的)
│ │ ├── components (可选的)
│ │ ├── theme (可选的)
│ │ │ └── Layout.vue
│ │ ├── public (可选的)
│ │ ├── styles (可选的)
│ │ │ ├── index.styl
│ │ │ └── palette.styl
│ │ ├── templates (可选的, 谨慎配置)
│ │ │ ├── dev.html
│ │ │ └── ssr.html
│ │ ├── config.js (可选的)
│ │ └── enhanceApp.js (可选的)
│ │
│ ├── README.md
│ ├── guide
│ │ └── README.md
│ └── config.md
│
└── package.json
注意
请留意目录名的大写。
docs/.vuepress
: 用于存放全局的配置、组件、静态资源等。docs/.vuepress/components
: 该目录中的Vue
组件将会被自动注册为全局组件。docs/.vuepress/theme
: 用于存放本地主题。docs/.vuepress/styles
: 用于存放样式相关的文件。docs/.vuepress/styles/index.styl
: 将会被自动应用的全局样式文件,会生成在最终的CSS
文件结尾,具有比默认样式更高的优先级。docs/.vuepress/styles/palette.styl
: 用于重写默认颜色常量,或者设置新的stylus
颜色常量。docs/.vuepress/public
: 静态资源目录。docs/.vuepress/templates
: 存储HTML
模板文件。docs/.vuepress/templates/dev.html
: 用于开发环境的HTML
模板文件。docs/.vuepress/templates/ssr.html
: 构建时基于Vue SSR
的HTML
模板文件。docs/.vuepress/config.js
: 配置文件的入口文件,也可以是YML
或toml
。docs/.vuepress/enhanceApp.js
: 客户端应用的增强。
大概过一下,现在看不懂没关系。
# 路由规则
事实上,一个 VuePress
网站是一个由 Vue
(opens new window)、Vue Router
(opens new window) 和 webpack
(opens new window) 驱动的单页应用。如果你以前使用过 Vue
的话,当你在开发一个自定义主题的时候,你会感受到非常熟悉的开发体验,你甚至可以使用 Vue DevTools
去调试你的自定义主题。
对于上述的目录结构,默认页面路由地址如下:
文件的相对路径 | 页面路由地址 |
---|---|
/README.md | / |
/guide/README.md | /guide/ |
/config.md | /config.html |
vuepress
的路由默认和根据文件结构一样的,READEME.md
的路由为 '/'
# 配置主页
# 基础配置
一个 VuePress
网站必要的配置文件是 .vuepress/config.js
- 在
docs
目录下创建一个.vuepress
的文件夹,文件夹中新建config.js
,内容如下:
module.exports = {
title: 'Hello VuePress',
description: 'Just playing around'
}
2
3
4
对于上述的配置,如果你运行起 dev server
,你应该能看到一个页面,它包含一个页头,里面包含一个标题和一个搜索框。
# 首页配置
docs/README.md
是这个文档的首页,内容修改如下:
---
home: true
heroImage: /img/home.jpg
heroText: 刀刀的知识积累
tagline: 懒散二字,立身之贼也。千德万业,日怠废而无成;干罪万恶,日横恣而无制,皆此二字为之。西晋仇礼法而乐豪放,病本正在此安肆日偷。安肆,懒散之谓也。此圣贤之大成也。
actionText: 立即学习 →
actionLink: /config
features:
- title: 简洁至上
details: 以 Markdown 为中心的项目结构,以最少的配置帮助你专注于写作。
- title: Vue驱动
details: 享受 Vue + webpack 的开发体验,在 Markdown 中使用 Vue 组件,同时可以使用 Vue 来开发自定义主题。
- title: 高性能
details: VuePress 为每个页面预渲染生成静态的 HTML,同时在页面被加载的时候,将作为 SPA 运行。
footer: MIT Licensed | Copyright © 2021-present 刀刀
---
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
重新启动一下项目,仔细体会一下这些配置的作用。
heroImage
的那张图片放在 .vuepress/public/img
下,是上文介绍过的静态资源目录。
# 配置导航栏
现在首页配置完了,但是首页上面的导航栏只有一个搜索框。
配置导航栏在.vuepress/config.js
中配置
# 导航栏Logo
// .vuepress/config.js
module.exports = {
themeConfig: {
logo: '/img/home.jpg',
}
}
2
3
4
5
6
# 导航栏链接
module.exports = {
themeConfig: {
logo: '/img/home.jpg',
nav: [
{ text: '主页', link: '/' },
{text: '前端学习',
items: [
{
text: '基础',
items:[
{text:'es6',link:'/es6/'},
{text:'ts',link:'/ts/'},
{text:'nodejs',link:'/nodejs'},
{text:'css',link:'/css/'}
]
},
{
text: '框架学习',
items:[
{text:'vue',link:'/vue/'},
{text:'react',link:'/react'},
{text:'vuePress',link:'/vuepress/'},
{text:'qiankun微前端',link:'/qiankun/'}
]
},
]
},
{ text: 'External', link: 'https://baidu.com', target:'_blank_', rel:'' }
],
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
导航可以是外部链接也可以是内部链接,外部链接可以加上target
和rel
属性,这是<a>
标签的两个属性
当你提供了一个 items
数组而不是一个单一的 link
时,它将显示为一个 下拉列表
此外,你还可以通过嵌套的 item
s 来在 下拉列表 中设置分组
# 配置侧边栏
先添加几篇文档。目录结构如下:
├── docs
│ ├── .vuepress
│ │ ├── public
│ │ └── config.js
│ │
│ ├── README.md
│ ├── page
│ │ ├── page1.md
│ │ ├── page2.md
│ │ └── group1
│ │ ├── page3.md
│ │ └── page4.md
│ ├── article
│ │ ├── article1.md
│ │ ├── article2.md
│ │ └── group2
│ │ ├── article3.md
│ │ └── article4.md
│ └── config.md
│
└── package.json
根据前面讲的路由规则,这几个页面的路由如下:
页面 | 路由 |
---|---|
page1.md | /page/page1 |
page2.md | /page/page2 |
page3.md | /page/group1/page3 |
page4.md | /page/group1/page4 |
article1.md | /article/article1 |
article2.md | /article/article2 |
article3.md | /article/group2/article3 |
article4.md | /article/group2/article4 |
# 配置静态侧边栏
关于配置侧边栏可以参考VuePress文档
我希望查看page
下的文章时,侧边栏只展示page
相关的链接,查看article
下的文章时,侧边栏只展示article
相关的链接。所以侧边栏的配置应该是这样的:
// .vuepress/config.js
module.exports = {
themeConfig: {
sidebar: {
'/page/': [
'/page/page1',
'/page/page2',
{
title: 'group1', // 必要的
collapsable: false, // 可选的, 默认值是 true,
sidebarDepth: 1, // 可选的, 默认值是 1
children: [
'/page/group1/page3',
'/page/group1/page4'
]
}
],
'/article/': [
'/article/article1',
'/article/article2',
{
title: 'group2', // 必要的
collapsable: false, // 可选的, 默认值是 true,
sidebarDepth: 1, // 可选的, 默认值是 1
children: [
'/article/group2/article3',
'/article/group2/article4'
]
}
],
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
侧边栏就配置好了。
# 动态生成侧边栏
然鹅,我们写的是个小博客,可能每天都要写好几篇新的文章,写死的侧边栏显然不可取,我们码农当然希望根据文档结构自动生成侧边栏。稍微改一下配置,如下:
- 创建
.vuepress/utils/getSidebarData.js
const fs = require("fs");
const path = require("path");
/**
* string比较工具类
*/
const str = {
contains: function (string, substr, isIgnoreCase) {
if (isIgnoreCase) {
string = string.toLowerCase();
substr = substr.toLowerCase();
}
var startChar = substr.substring(0, 1);
var strLen = substr.length;
for (var j = 0; j < string.length - strLen + 1; j++) {
if (string.charAt(j) == startChar) {
//如果匹配起始字符,开始查找
if (string.substring(j, j + strLen) == substr) {
//如果从j开始的字符与str匹配,那ok
return true;
}
}
}
return false;
}
};
/**
* 文件助手: 主要用于读取当前文件下的所有目录和文件
*/
const filehelper = {
getAllFiles: function (rpath) {
let filenames = []
fs.readdirSync(rpath).forEach(file => {
fullpath = rpath + "/" + file;
var fileinfo = fs.statSync(fullpath);
// 过滤 .DS_Store
if (fileinfo.isFile() && !str.contains(file, "DS_Store", true)) {
if (file === "README.md" || file === "readme.md") {
file = "";
} else {
file = file.replace(".md", "");
}
filenames.push(file);
}
});
filenames.sort();
return filenames;
},
getAllDirs: function getAllDirs(mypath = "docs") {
const items = fs.readdirSync(mypath);
let result = []
// 遍历当前目录中所有文件夹
items.map(item => {
let temp = path.join(mypath, item);
// 过滤无关的文件夹
if ( fs.statSync(temp).isDirectory() && !item.startsWith(".") && !str.contains(item, "DS_Store", true)) {
let path = item;
result.push(path)
}
});
return result;
}
};
// 侧边栏
var sidebar = {};
function genSideBar() {
//查找docs目录下的文件夹,排除掉.vuepress之类的配置文件
let firstFoder = filehelper.getAllDirs('docs')
for(let i = 0;i< firstFoder.length; i++){
//生成sidebar配置
sidebar["/"+firstFoder[i]+"/"] = getFileOrFolder('docs',firstFoder[i])
}
}
//运用递归生成子目录
function getFileOrFolder(root,path){
let arr = []
let foders = filehelper.getAllDirs(root+'/'+path)
let files = filehelper.getAllFiles(root+'/'+path)
files.forEach(item => arr.push('/'+path+'/'+item))
if(foders.length > 0){
foders.forEach(folder => {
arr.push({
title:folder,
sidebarDepth: 2, // 可选的, 默认值是 1
children:getFileOrFolder(root,path+"/"+folder)
})
})
}
return arr
}
genSideBar()
module.exports = sidebar;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
- 在
.vuepress/config.js
中导入刚刚生成的sidebar
const sidebar = require("./utils/getSidebarData")
module.exports = {
themeConfig: {
sidebar:sidebar
}
}
2
3
4
5
6
7
重启项目,动态侧边栏就成功了。
# 结尾
现在这个简简单单的博客项目就启动起来了,可以开心写文章了,撒花!