从零开始创建一个简单博客
# 创建简单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 而不是 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
 2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
警告
请留意目录名的大写。
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、Vue Router 和 webpack 驱动的单页应用。如果你以前使用过 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 时,它将显示为一个 下拉列表
此外,你还可以通过嵌套的 items 来在 下拉列表 中设置分组
# 配置侧边栏
先添加几篇文档。目录结构如下:
.
├── 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
 2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
根据前面讲的路由规则,这几个页面的路由如下:
| 页面 | 路由 | 
|---|---|
| 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文档 (opens new window)
我希望查看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:filterNumber(folder),
            sidebarDepth: 2,    // 可选的, 默认值是 1
            children:getFileOrFolder(root,path+"/"+folder)
          })
        })
      }
      return arr
    }
    /**
     * 过滤字符串中的数字
     * @param {字符串} str 
     */
    function filterNumber(str){
      const ret = /^[0-9]+./
      let txt = str.replace(ret,"")
      return txt
    }
    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
105
106
107
108
109
110
111
112
113
- 在
.vuepress/config.js中导入刚刚生成的sidebar 
    const sidebar = require("./utils/getSidebarData")
    module.exports = {
        themeConfig: {
            sidebar:sidebar
        }
    }
 2
3
4
5
6
7
重启项目,动态侧边栏就成功了。
# 结尾
现在这个简简单单的博客项目就启动起来了,可以开心写文章了,撒花!