当今大多数的团队都实现了前、后端分支。前端与后端的沟通都是通过接口来实现的(一般情况下都是webapi接口)。这种情况你肯定需要一个接口查询的帮助文档,这个当然用swagger都可以实现。但做为前端开发的我们是否也应该考虑把自己写的组件以帮助文档的方式公开都团队其他人员使用。就像iview,easyui等UI组件都有自己的帮助文档。今天我们都介绍一套工具(其中某些组件经过本人的改造)
一、需要的组件
1. Hexo:静态博客生成器
2. Hexo-theme-doc:基于Hexo实现的帮助文档类型的皮肤,并对其中的某些逻辑进行完善
3. lunr-languages:实现lunr搜索对多语言的支持
二、实现的效果

上述演示效果为本人开发的ko-easyui插件的帮助文档。你可以访问此地址查看https://ko-plugins.gitee.io/koeasyui/index.html
效果看上去是简单了点,但却能达到对一套UI组件的说明,也是不错的。
三、对插件的改造
3.1 Hexo-them-doc的改造
对components.jsx中触发搜索的参数进行调整如下(使用其更快的触发搜索):
1class SearchForm extends React.Component { 2 3 constructor (props) { 4 super(props); 5 } 6 7 handleKeyUp (e) { 8 9 if (query.length < 2) { return; } 10 11 } 12 13}
主要就是把query.length < 3改为query.length < 2。
然后,引入修改后的lunr-languages(支持中文搜索的控件),修正代码如下(search/build.js):
1let support = require('lunr-languages/lunr.stemmer.support'); 2let zhcn = require('lunr-languages/lunr.zhcn'); 3support(lunr); 4zhcn(lunr); 5module.exports = function build (ctx) { 6 const index = lunr(function () { 7 //添加对中文的支持 8 this.use(lunr.zhcn); 9 10 this.ref('id'); 11 this.field('title'); 12 this.field('body'); 13 } 14}
上述是缩减之后的代码,其中主要是对lunr.zhcn的使用。
3.2 lunr-languages的改造
对lunr-languages的改造,增加了lunr.zhcn.js文件,增加对中文搜索的支持,代码如下:
1/** 2 * lunr对中文分词的支持 3 */ 4; 5(function(root, factory) { 6 if (typeof define === 'function' && define.amd) { 7 // AMD. Register as an anonymous module. 8 define(factory) 9 } else if (typeof exports === 'object') { 10 /** 11 * Node. Does not work with strict CommonJS, but 12 * only CommonJS-like environments that support module.exports, 13 * like Node. 14 */ 15 module.exports = factory() 16 } else { 17 // Browser globals (root is window) 18 factory()(root.lunr); 19 } 20}(this, function() { 21 /** 22 * Just return a value to define the module export. 23 * This example returns an object, but the module 24 * can return a function as the exported value. 25 */ 26 return function(lunr) { 27 /* throw error if lunr is not yet included */ 28 if ('undefined' === typeof lunr) { 29 throw new Error('Lunr is not present. Please include / require Lunr before this script.'); 30 } 31 32 /* throw error if lunr stemmer support is not yet included */ 33 if ('undefined' === typeof lunr.stemmerSupport) { 34 throw new Error('Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.'); 35 } 36 37 /* 38 Thai tokenization is the same to Japanense, which does not take into account spaces. 39 So, it uses the same logic to assign tokenization function due to different Lunr versions. 40 */ 41 var isLunr2 = lunr.version[0] == "2"; 42 43 /* register specific locale function */ 44 lunr.zhcn = function() { 45 this.pipeline.reset(); 46 this.pipeline.add( 47 lunr.zhcn.trimmer, 48 lunr.zhcn.stopWordFilter, 49 lunr.zhcn.stemmer 50 ); 51 52 if (isLunr2) { // for lunr version 2.0.0 53 this.tokenizer = lunr.zhcn.tokenizer; 54 } else { 55 if (lunr.tokenizer) { // for lunr version 0.6.0 56 lunr.tokenizer = lunr.zhcn.tokenizer; 57 } 58 if (this.tokenizerFn) { // for lunr version 0.7.0 -> 1.0.0 59 this.tokenizerFn = lunr.zhcn.tokenizer; 60 } 61 } 62 }; 63 64 65 var segmenter = new lunr.TinySegmenter(); 66 67 lunr.zhcn.tokenizer = function(obj) { 68 var i; 69 var str; 70 var len; 71 var segs; 72 var tokens; 73 var char; 74 var sliceLength; 75 var sliceStart; 76 var sliceEnd; 77 var segStart; 78 79 if (!arguments.length || obj == null || obj == undefined) 80 return []; 81 82 if (Array.isArray(obj)) { 83 return obj.map( 84 function(t) { 85 return isLunr2 ? new lunr.Token(t.toLowerCase()) : t.toLowerCase(); 86 } 87 ); 88 } 89 90 str = obj.toString().toLowerCase().replace(/^\s+/, ''); 91 for (i = str.length - 1; i >= 0; i--) { 92 if (/\S/.test(str.charAt(i))) { 93 str = str.substring(0, i + 1); 94 break; 95 } 96 } 97 98 tokens = []; 99 len = str.length; 100 for (sliceEnd = 0, sliceStart = 0; sliceEnd <= len; sliceEnd++) { 101 char = str.charAt(sliceEnd); 102 sliceLength = sliceEnd - sliceStart; 103 104 if ((char.match(/\s/) || sliceEnd == len)) { 105 if (sliceLength > 0) { 106 segs = segmenter.segment(str.slice(sliceStart, sliceEnd)).filter( 107 function(token) { 108 return !!token; 109 } 110 ); 111 112 segStart = sliceStart; 113 for (i = 0; i < segs.length; i++) { 114 if (isLunr2) { 115 tokens.push( 116 new lunr.Token( 117 segs[i], { 118 position: [segStart, segs[i].length], 119 index: tokens.length 120 } 121 ) 122 ); 123 } else { 124 tokens.push(segs[i]); 125 } 126 segStart += segs[i].length; 127 } 128 } 129 130 sliceStart = sliceEnd + 1; 131 } 132 } 133 134 return tokens; 135 } 136 137 lunr.zhcn.stemmer = (function(){ 138 return function(word) { 139 return word; 140 } 141 })(); 142 143 lunr.Pipeline.registerFunction(lunr.zhcn.stemmer, 'stemmer-zhcn'); 144 145 /* lunr trimmer function */ 146 lunr.zhcn.wordCharacters = "一二三四五六七八九十百千万億兆一-龠々〆ヵヶぁ-んァ-ヴーア-ン゙a-zA-Za-zA-Z0-90-9"; 147 lunr.zhcn.trimmer = lunr.trimmerSupport.generateTrimmer(lunr.zhcn.wordCharacters); 148 lunr.Pipeline.registerFunction(lunr.zhcn.trimmer, 'trimmer-zhcn'); 149 150 151 /* lunr stop word filter. see https://www.ranks.nl/stopwords/chinese-stopwords */ 152 lunr.zhcn.stopWordFilter = lunr.generateStopWordFilter('的 一 不 在 人 有 是 为 以 于 上 他 而 后 之 来 及 了 因 下 可 到 由 这 与 也 此 但 并 个 其 已 无 小 我 们 起 最 再 今 去 好 只 又 或 很 亦 某 把 那 你 乃 它 吧 被 比 别 趁 当 从 到 得 打 凡 儿 尔 该 各 给 跟 和 何 还 即 几 既 看 据 距 靠 啦 了 另 么 每 们 嘛 拿 哪 那 您 凭 且 却 让 仍 啥 如 若 使 谁 虽 随 同 所 她 哇 嗡 往 哪 些 向 沿 哟 用 于 咱 则 怎 曾 至 致 着 诸 自'.split(' ')); 153 lunr.Pipeline.registerFunction(lunr.zhcn.stopWordFilter, 'stopWordFilter-zhcn'); 154 }; 155}))