使用npm安裝jsdoc後,其文件目錄結構以下:
其中templates放置了默認的主題模板。其中default主題的文件結構以下:
其中,publish.js是最重要的文件,它導出一個publish
函數,在cli.js
中被調用html
// cli.js publishPromise = template.publish( // 保存全部數據的Taffy對象,見下面 taffy(props.docs), // env是一個保存運行環境信息的對象 // 參考:lib/jsdoc/env.js env.opts, // 暫時未 resolver.root ); // publish.js // 這裏的publish就是上面的template.publish exports.publish = function (taffyData, opts, tutorials) { // ... }
參考:taffydb
而static文件夾放置靜態文件,它會被原封不動地複製到生成的文件夾中,tmpl是模板文件npm
function (taffyData, opts, tutorials)
taffyData是包含全部doclet對象的taffy對象,參考doclet.js,
多數和@description,@example等對應。name指代當前@kind的名字json
和模板相關的模塊是:函數
const template = require('jsdoc/template'); // 模板定義 const helper = require('jsdoc/util/templateHelper'); // 模板的輔助函數庫
生成template的語句是ui
// templatePath是配置文件中的opts.template或者使用cli時的template選項的值 // 它應該是模板文件夾`tmpl`的所在文件夾的路徑`(主題文件夾的根目錄)` view = new template.Template( path.join(templatePath, 'tmpl') );
再看template.js導出類的構造函數this
constructor(filepath) { // 模板文件所在路徑 this.path = filepath; // layout的文件名 this.layout = null; // 代表使用的模板語法 this.settings = { evaluate: /<\?js([\s\S]+?)\?>/g, interpolate: /<\?js=([\s\S]+?)\?>/g, escape: /<\?js~([\s\S]+?)\?>/g }; }
layout的初始化語句:lua
// env.conf是配置文件導出的對象 conf = env.conf.templates || {}; conf.default = conf.default || {}; // .... // 設置layout的路徑 view.layout = conf.default.layoutFile ? path.getResourcePath(path.dirname(conf.default.layoutFile), path.basename(conf.default.layoutFile) ) : 'layout.tmpl';
因此,若是要自定義模板(假設爲selfTheme,如下都以其爲例)的配置項,只須要使用env.conf.templates
獲取便可。例如:url
// conf.json { templates: { selfProp: 'selfValue' } } // publish.js conf = env.conf.templates || {}; conf.selfProp = conf.selfProp; // get selfProp
template.js導出類的方法以下:spa
重點看render代碼:code
render(file, data) { // 渲染當前模板文件 let content = this.partial(file, data); if (this.layout) { // 將當前內容賦值給data.content,傳遞給layout模板 data.content = content; content = this.partial(this.layout, data); } return content; }
所以,在layout.tmpl文件中,有content變量表示當前頁內容
<?js= content ?>
固然,同時具備data包含的其它屬性變量
在publish.js中,直接使用render函數的有兩處。
// function generate(title, docs, filename, resolveLinks) docData = { env: env, title: title, // 標題 docs: docs // 見下面docs }; html = view.render('container.tmpl', docData); // function generateTutorial(title, tutorial, filename) const tutorialData = { title: title, header: tutorial.title, content: tutorial.parse(), children: tutorial.children }; const tutorialPath = path.join(outdir, filename); let html = view.render('tutorial.tmpl', tutorialData);
因此,要修改各頁面的標題,只須要將調用這兩個函數的title函數換掉,好比:
generate('Global', [{kind: 'globalobj'}], globalUrl) // 改爲 generate('MyGlobal', [{kind: 'globalobj'}], globalUrl)
不太重點仍是添加模板變量和方法
// 添加變量,只須要改變render調用時的data,好比如下改變container.tmpl的變量 docData = { env: env, title: title, // 標題 docs: docs, myVar: 'myVar' }; html = view.render('container.tmpl', docData); // 添加方法 view.find = find; view.linkto = linkto; view.resolveAuthorLinks = resolveAuthorLinks; view.tutoriallink = tutoriallink; view.htmlsafe = htmlsafe; view.outputSourceFiles = outputSourceFiles; view.nav = buildNav(members); // 在模板中可使用`this.method`來調用,由於模板的this指向view // 好比 // <?js this.find() ?>
添加到view中的方法/屬性:
經過find({kind: 'class'})來獲取全部class,也能夠添加其它doclet:find({kind, 'class', memberOf: 'Class1' })
渲染一個跳轉到longname
)即namepath所指代的url的連接(a標籤),文本是linkText
resolveAuthorLinks
渲染形如Jane Doe <jdoe@example.org>
的文本爲<a href="mailto:jdoe@example.org">Jane Doe</a>
docs是一個包含數據的Taffy對象,它的來源是:
data = taffyData // 獲取各部分的數據taffy對象 members = helper.getMembers(data) classes = taffy(members.classes); modules = taffy(members.modules); namespaces = taffy(members.namespaces); mixins = taffy(members.mixins); externals = taffy(members.externals); interfaces = taffy(members.interfaces); // 獲取對應longname的docs const myClasses = helper.find(classes, {longname: longname}); const myExternals = helper.find(externals, {longname: longname}); const myInterfaces = helper.find(interfaces, {longname: longname}); const myMixins = helper.find(mixins, {longname: longname}); const myModules = helper.find(modules, {longname: longname}); const myNamespaces = helper.find(namespaces, {longname: longname});
// myClasses等就是傳入模板文件的docs變量
if (myModules.length) { generate(`Module: ${myModules[0].name}`, myModules, helper.longnameToUrl[longname]); } if (myClasses.length) { generate(`Class: ${myClasses[0].name}`, myClasses, helper.longnameToUrl[longname]); } if (myNamespaces.length) { generate(`Namespace: ${myNamespaces[0].name}`, myNamespaces, helper.longnameToUrl[longname]); } if (myMixins.length) { generate(`Mixin: ${myMixins[0].name}`, myMixins, helper.longnameToUrl[longname]); } if (myExternals.length) { generate(`External: ${myExternals[0].name}`, myExternals, helper.longnameToUrl[longname]); } if (myInterfaces.length) { generate(`Interface: ${myInterfaces[0].name}`, myInterfaces, helper.longnameToUrl[longname]); }
在模板中則用this.find({kind: 'class'})代替(view.find)
docs的元素內容是:
// 參考doclet.js { comment: '' name: '',, kind: '', // ... }
特別的:
// source { kind: 'source', code: '' } // main page { kind: 'mainpage', readme: opts.readme, longname: (opts.mainpagetitle) ? opts.mainpagetitle : 'Main Page' } // global { kind: 'globalobj' }
tutorials相關待續