原文链接: https://juejin.cn/post/6844903497893150734
安装
// 安装docsify-cli
npm install docsify-cli -g
初始化
@desc: 初始化 docsify,将模板文件拷贝至 path 下
@param:local[boolean],local 默认为 false,若设置为 true,则将 js,css 等资源文件拷贝到本地 path 下的 vendor 目录下.
@param:theme[string], theme 默认为'vue',主题可选'buble','dark','pure','vue'.
docsify init <path> [--local] [--theme]
- or -
docsify i <path> [-l] [-t]
部署服务
@desc: 初始化 docsify 后,才能部署 docsify,否则会报出下方的 errorMsg
@errorMsg: No docs found, please run docsify init first.
@param: open[boolean],默认为 false,若为 true,则部署后自动打开默认浏览器该站点地址.
@param: port[number],默认为 3000,可自定义其他未被占用的端口.
docsify serve <path> [--open] [--port]
-- or --
docsify s <path> [-o] [-p]
一键生成
- 生成初始模板页面结构配置,若能通过 config 读取到配置文件,那么合并至模板页面结构配置,若未读取到,则检查 path 下是否有 package.json,并读取 package.json 中的 docsify 配置,若配置存在,则合并,否则用初始的模板页面结构配置。
- 文档通过服务端渲染输出
- 没有 serve 模式下的热加载,所谓热加载,即监控文件更改并重新加载浏览器(对于部署在远程服务器上来说,最好别用热加载)
@desc: 一键生成文档站点.
@param: config[string],默认为 false, 需要加载的配置文件,可自定义 docsify 配置.
@param: port[number],默认为 4000,可自定义其他未被占用的端口.
docsify start <path> [--config] [--port]
--- or ---
docsify start <path> [-c] [-p]
Docsify 源码解读
TOC: table of contents
初始化工作
首先通过
initMixin、routerMixin、renderMixin、fetchMixin、eventMixin等方法向 Docsify 对象原型注入方法和属性然后初始化全局对象 Docsify、DocsifyCompiler、marked、Prism,即挂载到 window 对象之上。
dom 加载完成触发回调事件 this._init()
initMixin
export function initMixin(proto) {
// proto为Docsify原型对象
proto._init = function () {
const vm = this;
vm.config = config || {};
initLifecycle(vm); // Init hooks
initPlugin(vm); // Install plugins
callHook(vm, 'init');
initRouter(vm); // Add router
initRender(vm); // Render base DOM
initEvent(vm); // Bind events
initFetch(vm); // Fetch data
callHook(vm, 'mounted');
};
}
initLifycycle
这里定义了六个钩子函数,即 init、beforeEach、afterEach、doneEach、ready、mounted,钩子函数初始化为空数组。下面介绍下钩子的生命周期:
- init: 仅在第一次初始化页面时调用。
- beforeEach: 开始解析 Markdown 内容时前调用。
- afterEach: markdown 解析成 html 后调用。beforeEach 和 afterEach 支持异步处理,通过回调返回结果。
- doneEach: 路由切换后数据全部加载完成后调用
- ready: 首次初始化页面且加载完数据后调用。
- mounted: 渲染完成后调用
initPlugin
引入用户自定义插件,及其设置的钩子函数,来替换默认钩子函数。
callHook(vm,'init')
调用"init"钩子函数,vm 为当前实例。
initRouter
设置路由模式,默认为'hash',用户可设置为'history'或'hash'。
initRender
这里主要为编译层,初始化 markdown 编译器,重写了 marked 的一些标签编译方法,例如 heading、code、link、paragraph、image 等,最终生成 app 的 DOM 实例,并添加到 DOM 中(注意:此时 Content、navbar 和 sidebar 仅仅是模板实例,内容数据还未获取)。
initEvent
为切换 sidebar 的按钮绑定事件。
initFetch
通过 xhr 请求获取 sidebar、navbar、content、coverpage 的 text 数据,然后填充进 DOM 实例中。
callHook(vm,'mounted')
调用"mounted"钩子函数,vm 为当前实例。
routerMixin
export function routerMixin(proto) {
// proto为Docsify原型对象
proto.route = {};
}
router 模块初始化仅仅定义了一个名为 route 的 Docsify 原型对象的对象属性。
renderMixin
export function renderMixin (proto) {
// proto为Docsify原型对象,下面代码细节就不讲了,感兴趣的话可以down一份研究下
proto._renderTo = function (el, content, replace) {
// 如何插入content,replace = ['outerHTML'|'innerHTML']
...
}
proto._renderSidebar = function (text) {
// 读取并解析sidebar配置,渲染sidebar
...
}
proto._bindEventOnRendered = function (activeEl) {
// 滚动条滑动模块,以及对配置项autoHeader、auto2top的处理
...
}
proto._renderNav = function (text) {
// 渲染navbar内容,处理nav上活动标签样式
...
}
proto._renderMain = function (text, opt = {}) {
// 渲染content内容: 首先调用beforeEach钩子,然后将markdown编译成html,最后调用afterEach处理后返回html,最后渲染content
// 然后读取excuteScript配置,若为true,则执行script内嵌脚本。若想执行外链脚本,需要引入external-script插件
...
}
proto._renderCover = function (text) {
// 渲染封面页
...
}
proto._updateRender = function () {
// 渲染文档站点标题
...
}
}
fetchMixin
export function fetchMixin (proto) {
// 同renderMixin的proto所述
let last // 记录上一次请求信息
proto._fetch = function (cb = noop) {
... // 强制结束上一次请求,加载content、nav以及sidebar数据
}
proto._fetchCover = function () {
... // 请求并渲染封面数据
}
proto.$fetch = function (cb = noop) {
... // 封装了一个方法用作路由切换的数据请求
}
}
eventMixin
export function eventMixin(proto) {
// 同renderMixin的proto所述
proto.$resetEvents = function () {
// 滚动到当前路由中id='query.id'的dom块,并使sidebar的活动标签实时响应,获取nav活动标签
scrollIntoView(this.route.query.id);
sidebar.getAndActive(this.router, 'nav');
};
}
initGlobalAPI
export default function () {
window.Docsify = { util, dom, get, slugify };
window.DocsifyCompiler = Compiler;
window.marked = marked;
window.Prism = prism;
}
这里导出一个方法,里面主要暴露了四个全局对象,方便提供使用。
- window.Docsify 对象包含了工具类方法->util、 dom 操作方法->dom、 请求 markdown 内容方法->get、 缓存处理方法->slugify
- window.DocsifyCompiler 为构造函数生成的对象,是对开源项目 marked 做了一些扩展性,自定义了一些如前文所述的标签编译方法。
- window.marked 即如上所述的 marked 对象
- window.Prism 即开源项目 prism,一个轻量级,强大,优雅的语法高亮库。
最后
- 若要配置到远程服务器的话且在 serve 模式下,可在 serve 手动关掉 livereload,因为它会单独开启一个端口服务来监控文件更改。
- 服务端渲染(SSR),主要依赖 Docsify 的 docsify -server -renderer 模块

TEST4
TEST3
TEST2
TEST