<p><code></p> <h2 id="articleHeader0">症结(懒癌患者)</h2> <p>在写组件库文档的时候,会把示例代码粘贴到文档里,这样做有一个很恶心的地方:每次组件迭代或修改示例都需要重新修改文档中的代码片段。长年累月,苦不堪言。</p> <h2 id="articleHeader1">猜想(狂想曲)</h2> <p>所以我想,可不可以把.vue文件里的template块和script块取出来,放入对应的.md文件中</p> <p>比如在.md文件中 <code>{{:xx.vue?type=(template|script)}}</code> 便替换示例中对应的<code>template|script</code>块</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="# xx ## 示例代码 // {{:}} 定义变量规则模版(加个冒号防冲突) {{:image.vue?type=template}} // 对应.vue 的template {{:image.vue?type=script}} // 对应.vue 的script {{:index.js}} // 对应index.js ## 参数说明 xxx..." title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs objectivec"><code><span class="hljs-meta"># xx</span> <span class="hljs-meta">## 示例代码</span> <span class="hljs-comment">// {{:}} 定义变量规则模版(加个冒号防冲突)</span> {{:image.vue?type=template}} <span class="hljs-comment">// 对应.vue 的template</span> {{:image.vue?type=script}} <span class="hljs-comment">// 对应.vue 的script</span> {{:index.js}} <span class="hljs-comment">// 对应index.js</span> <span class="hljs-meta">## 参数说明</span> xxx...</code></pre> <p>output</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="# xx ## 示例代码 // image.vue template <template></p> <div>xx</div> <p></template></p> <p>// image.vue script<br /> <script> ... </script></p> <p>// index.js</p> <p>var x = 1</p> <p>## 参数说明</p> <p>xxx..." title="" data-original-title="复制"></span> </div> </p></div> <pre class="xml hljs"><code class="html"># xx ## 示例代码 // image.vue template <span class="hljs-tag">&lt;<span class="hljs-name">template</span>&gt;</span> <span class="hljs-tag">&lt;<span class="hljs-name"><a href="http://www.js-code.com/tag/div" title="浏览关于“div”的文章" target="_blank" class="tag_link">div</a></span>&gt;</span>xx<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> <span class="hljs-tag">&lt;/<span class="hljs-name">template</span>&gt;</span> // image.vue script <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="undefined"> ... </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span> // index.js var x = 1 ## 参数说明 xxx...</code></pre> <h2 id="articleHeader2">动手(能动手绝不**)</h2> <p>要实现以上功能,需要探索以下几点:</p> <ul> <li>从<code>.vue</code>里取出template&amp;script</li> <li>塞进对应的<code>.md</code>的变量位置</li> <li>将<code>.md</code>文件转为<a href="http://www.js-code.com/tag/vue" title="Vue" target="_blank">Vue</a> Componet / html</li> </ul> <p>如果按照我们写js的习惯,以下嵌套排列可能更易读</p> <ul> <li> <p>将<code>.md</code>文件转为<a href="http://www.js-code.com/tag/vue" title="Vue" target="_blank">Vue</a> Componet / html</p> <ul> <li> <p>找到变量位置,塞进对应的<code>.md</code>的指定位置</p> <ul> <li>从<code>.vue</code>里取出template&amp;script</li> </ul> </li> </ul> </li> </ul> <p>一步一步来吧:</p> <h3 id="articleHeader3">1、将.md文件转为<a href="http://www.js-code.com/tag/vue" title="浏览关于“Vue”的文章" target="_blank" class="tag_link">Vue</a> Componet / html</h3> <p>要想在vue中使用<code>.md</code>文件为组件,只需要用<code>loader</code>将<code>md</code>转成Vue Componet即可。</p> <p>这个过程很简单,以下为loader伪代码</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="const wrapper = content => `<br /> <template></p> <section v-html=&quot;content&quot; v-once ></section> <p></template><br /> <script> <a href="http://www.js-code.com/tag/export" title="export" target="_blank">export</a> default { created() { <a href="http://www.js-code.com/tag/this" title="this" target="_blank">this</a>.content = content } }; </script><br /> `<br /> module.exports = function(source) {<br /> // markdown 编译用的 markdown-it<br /> return wrapper(new MarkdownIt().render(source))<br /> }" title="" data-original-title="复制"></span> </div> </p></div> <pre class="javascript hljs"><code class="javascript"><span class="hljs-keyword"><a href="http://www.js-code.com/tag/const" title="浏览关于“const”的文章" target="_blank" class="tag_link">const</a></span> wrapper = <span class="hljs-function"><span class="hljs-params">content</span> =&gt;</span> <span class="hljs-string">` &lt;template&gt; &lt;section v-html="content" v-once /&gt; &lt;/template&gt; &lt;script&gt; <a href="http://www.js-code.com/tag/export" title="浏览关于“export”的文章" target="_blank" class="tag_link">export</a> default { created() { <a href="http://www.js-code.com/tag/this" title="浏览关于“this”的文章" target="_blank" class="tag_link">this</a>.content = content } }; &lt;/script&gt; `</span> <span class="hljs-built_in">module</span>.exports = <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">source</span>) </span>{ <span class="hljs-comment">// markdown 编译用的 markdown-it</span> <span class="hljs-keyword">return</span> wrapper(<span class="hljs-keyword">new</span> MarkdownIt().render(source)) }</code></pre> <h3 id="articleHeader4">2、找到变量位置,塞进对应的.md的指定位置</h3> <h4>1)找到变量位置</h4> <p>使用正则匹配定义的规则,找到被<code>{{:}}</code> 包围的字符串,如上例所示则为<code>‘image.vue?type=template’</code></p> <h4>2)读取文件</h4> <p>如果是其他<code>.js</code>、<code>.html</code>等普通文件,直接使用<code>fs.readFileSync</code>读取替换即可,因是<code>.vue</code>,我们希望传入<strong>type</strong>来获取不同的块(template、script等)</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="const replaceResults = (template, baseDir) => {<br /> const regexp = new RegExp(&quot;\{\{:([^\}]+)\}\}&quot;, &quot;g&quot;)<br /> return template.replace(regexp, function(match) {<br /> // 获取文件变量<br /> match = match.substr(3, match.length - 5)<br /> let [loadFile, query=''] = match.split('?')<br /> // 读取文件内容<br /> const source = fs.readFileSync(path.join(baseDir, loadFile), &quot;utf-8&quot;).replace(/[rn]*$/, &quot;&quot;)<br /> if (path.extname(loadFile) === &quot;.vue&quot;) {<br /> let { type } = loaderUtils.parseQuery(`?${query}`)<br /> return replaceVue(source, type) // 根据type提取.vue里的不同块<br /> }<br /> return source // 非.vue直接返回文件内容<br /> })<br /> };" title="" data-original-title="复制"></span> </div> </p></div> <pre class="javascript hljs"><code class="javascript"><span class="hljs-keyword">const</span> replaceResults = <span class="hljs-function">(<span class="hljs-params">template, baseDir</span>) =&gt;</span> { <span class="hljs-keyword">const</span> regexp = <span class="hljs-keyword">new</span> <span class="hljs-built_in">RegExp</span>(<span class="hljs-string">"\{\{:([^\}]+)\}\}"</span>, <span class="hljs-string">"g"</span>) <span class="hljs-keyword">return</span> template.replace(regexp, <span class="hljs-function"><span class="hljs-keyword">function</span>(<span class="hljs-params">match</span>) </span>{ <span class="hljs-comment">// 获取文件变量</span> match = match.substr(<span class="hljs-number">3</span>, match.length - <span class="hljs-number">5</span>) <span class="hljs-keyword"><a href="http://www.js-code.com/tag/let" title="浏览关于“let”的文章" target="_blank" class="tag_link">let</a></span> [loadFile, query=<span class="hljs-string">''</span>] = match.split(<span class="hljs-string">'?'</span>) <span class="hljs-comment">// 读取文件内容</span> <span class="hljs-keyword">const</span> source = fs.readFileSync(path.join(baseDir, loadFile), <span class="hljs-string">"utf-8"</span>).replace(<span class="hljs-regexp">/[rn]*$/</span>, <span class="hljs-string">""</span>) <span class="hljs-keyword">if</span> (path.extname(loadFile) === <span class="hljs-string">".vue"</span>) { <span class="hljs-keyword">let</span> { type } = loaderUtils.parseQuery(<span class="hljs-string">`?<span class="hljs-subst">${query}</span>`</span>) <span class="hljs-keyword">return</span> replaceVue(source, type) <span class="hljs-comment">// 根据type提取.vue里的不同块</span> } <span class="hljs-keyword">return</span> source <span class="hljs-comment">// 非.vue直接返回文件内容</span> }) };</code></pre> <h3 id="articleHeader5">3、从.vue里取出template&amp;script</h3> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="const replaceVue = (source, type) => {<br /> const descriptor = templateCompiler.parseComponent(source)<br /> const lang = {<br /> template: 'html',<br /> script: 'javascript' //,<br /> // style: 'css'<br /> }<br /> return lang[type] &amp;&amp; `<br /> ```${lang[type]}<br /> ${descriptor[type].content}<br /> ```<br /> `<br /> }" title="" data-original-title="复制"></span> </div> </p></div> <pre class="javascript hljs"><code class="javascript"><span class="hljs-keyword">const</span> replaceVue = <span class="hljs-function">(<span class="hljs-params">source, type</span>) =&gt;</span> { <span class="hljs-keyword">const</span> descriptor = templateCompiler.parseComponent(source) <span class="hljs-keyword">const</span> lang = { <span class="hljs-attr">template</span>: <span class="hljs-string">'html'</span>, <span class="hljs-attr">script</span>: <span class="hljs-string">'javascript'</span> <span class="hljs-comment">//,</span> <span class="hljs-comment">// style: 'css'</span> } <span class="hljs-keyword">return</span> lang[type] &amp;&amp; <span class="hljs-string">` ```<span class="hljs-subst">${lang[type]}</span> <span class="hljs-subst">${descriptor[type].content}</span> ``` `</span> }</code></pre> <p>如若要取一个文件里的多个块,则需多次调用,考虑到我们的组件库场景,默认返回template和script(未使用type参数时),<br />对上面代码进行优化,一次性从<code>.vue</code>中取出多个块</p> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="// replaceVue(source, [type]) const replaceVue = (source, types = ['template', 'script']) => {<br /> const descriptor = templateCompiler.parseComponent(source)<br /> const lang = {<br /> template: 'html',<br /> script: 'javascript' //,<br /> // style: 'css'<br /> }<br /> return types.map(type => lang[type] &amp;&amp; `<br /> ```${lang[type]}<br /> ${descriptor[type].content}<br /> ```<br /> `).join('')<br /> }" title="" data-original-title="复制"></span> </div> </p></div> <pre class="javascript hljs"><code class="javascript"><span class="hljs-comment">// replaceVue(source, [type])</span> <span class="hljs-keyword">const</span> replaceVue = <span class="hljs-function">(<span class="hljs-params">source, types = [<span class="hljs-string">'template'</span>, <span class="hljs-string">'script'</span>]</span>) =&gt;</span> { <span class="hljs-keyword">const</span> descriptor = templateCompiler.parseComponent(source) <span class="hljs-keyword">const</span> lang = { <span class="hljs-attr">template</span>: <span class="hljs-string">'html'</span>, <span class="hljs-attr">script</span>: <span class="hljs-string">'javascript'</span> <span class="hljs-comment">//,</span> <span class="hljs-comment">// style: 'css'</span> } <span class="hljs-keyword">return</span> types.map(<span class="hljs-function"><span class="hljs-params">type</span> =&gt;</span> lang[type] &amp;&amp; <span class="hljs-string">` ```<span class="hljs-subst">${lang[type]}</span> <span class="hljs-subst">${descriptor[type].content}</span> ``` `</span>).join(<span class="hljs-string">''</span>) }</code></pre> <p>大功告成????????! 那么,如何使用呢?</p> <h2 id="articleHeader6">使用(给我小星星<span style="font-weight:normal;">????</span>)</h2> <h3 id="articleHeader7">安装</h3> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="npm i vue-markd-loader -D" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs nginx"><code style="word-break: break-word; white-space: initial;"><span class="hljs-attribute">npm</span> i vue-markd-loader -D</code></pre> <h3 id="articleHeader8">配置</h3> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="rules: [{ test: /.md$/, use: [ 'vue-loader', { loader: 'vue-markd-loader', options: { replaceFiles: true , // 默认true, 是否将文件填充进md wrapper:true // 默认true,默认输出Vue Component ,false 时输出html片段 } } ] }]" title="" data-original-title="复制"></span> </div> </p></div> <pre class="hljs groovy"><code><span class="hljs-string">rules:</span> [{ <span class="hljs-symbol"> test:</span> <span class="hljs-regexp">/.md$/</span>, <span class="hljs-symbol"> use:</span> [ <span class="hljs-string">'vue-loader'</span>, { <span class="hljs-symbol"> loader:</span> <span class="hljs-string">'vue-markd-loader'</span>, <span class="hljs-symbol"> options:</span> { <span class="hljs-symbol"> replaceFiles:</span> <span class="hljs-literal">true</span> , <span class="hljs-comment">// 默认true, 是否将文件填充进md</span> <span class="hljs-symbol"> wrapper:</span><span class="hljs-literal">true</span> <span class="hljs-comment">// 默认true,默认输出Vue Component ,false 时输出html片段 </span> } } ] }]</code></pre> <div class="widget-codetool" style="display:none;"> <div class="widget-codetool--inner"> <span class="selectCode code-tool" data-toggle="tooltip" data-placement="top" title="" data-original-title="全选"></span><br /> <span type="button" class="copyCode code-tool" data-toggle="tooltip" data-placement="top" data-clipboard-text="// main.js import 'highlight.js/styles/github.css' // 可以使用任意喜欢的主题哟 import 'github-markdown-css'" title="" data-original-title="复制"></span> </div> </p></div> <pre class="javascript hljs"><code class="javascript"><span class="hljs-comment">// main.js </span> <span class="hljs-keyword">import</span> <span class="hljs-string">'highlight.js/styles/github.css'</span> <span class="hljs-comment">// 可以使用任意喜欢的主题哟</span> <span class="hljs-keyword">import</span> <span class="hljs-string">'github-markdown-css'</span></code></pre> <h2 id="articleHeader9">其他</h2> <p>第一次撸<code>webpack loader</code>,如有不正确/不足的地方,欢迎指正。</p> <ul> <li><a href="https://github.com/zq741235/vue-markd-loader" rel="nofollow noreferrer" target="_blank">源代码git地址</a></li> <li><a href="https://www.npmjs.com/package/vue-markd-loader" rel="nofollow noreferrer" target="_blank">npm包地址</a></li> </ul> <p></code></p>

本文固定链接: http://www.js-code.com/vue-js/vue-js_25683.html