はじめに
プロジェクトでは、コンポーネントは通常、多くのことを書かなければならないが、各コンポーネントの使用方法は、通常、ドキュメントの同様の要素-UIの説明に行くことはありません。だから、新人が引き継ぐとき、彼らは一般的なコンポーネントを直接無視するか、複雑なコンポーネントの使い方を知るために半日読まなければなりません。
19年の前半に、私はウィジェットライブラリを書きました、目的は、共通のコンポーネントだけでなく、スタイルの会社の複数のプロジェクトを統一し、ドキュメントの説明を与えることです。 しかし、このウィジェットライブラリのドキュメントは少し問題があり、同じページには、1つのvueのみ許可されています。
最近、自分のことを整理し、最大この作品のアイデアを向上させるために、インターネット上の既存のソリューションをチェックアウトし、vuepressフレームワークを使用して、その後、高い人々の実装と組み合わせてWebページを達成するために同時に例のコードと効果を示すために、利害関係者は見続けることができます。
プリンシプル
vuepressは、マークダウン・ファイルの中に直接vueのコードを書くことをサポートしています。そして、コードとコードの効果の共存を実現するために、最も簡単な方法は、コードのコピーを2つ書くことです。人間の進歩の大部分は、コードの一部を2度書いてコピーし、ドキュメントの見栄えを悪くしたくないという怠惰から生まれます。これがその怠惰な方法です。
既存のプログラム
方法I:
Vuepressを使用して、componentsディレクトリにコンポーネントを自動的に登録するか、enhanceApp.jsフックを使用してサンプルコードファイルを自分で登録し、<< @/filepath構文を使用してサンプルコードファイルを取り込みます。この方法の欠点は、コンポーネントをグローバルに登録する必要があることです。
<color-picker-basic-demo></color-picker-basic-demo>
## サンプルコードは以下の通り: wfwfwf.github.io/vue-blog/di
```html
<<< @/docs/.vuepress/components/color-picker-basic-demo.vue
方法II:
vuepressにもライフサイクルがあって、vuepressのプラグインを書いて、プラグインの中でコードを分割して組み立てて、data-にフォーマットで保存して、vuepressが更新されたらvue.extendでインスタンスを作って対応する要素にマウントします。gitでvuepress-plugin-demo-block-masterと検索すると出てきます!
個人的にはこの方法はあまり好きではなく、es6のコードを変換するためにbableを使ったり、elementuiなどのコンポーネントライブラリを導入する必要があり、これもちょっと面倒です。
方法3:
vuepressを使用しない場合は、td-addonで使用した方法に似た独自のローダーを書くことになりますが、対応するコードを改善する必要があります。 vuepressのコードを使用すると、vuepressはプラグイン拡張をサポートしており、その設定ファイル..../.vuepress/config.jsに、プラグインを追加することで、独自のプラグインを書くことができ、このプラグインで、マークダウンファイルの前処理を行うことができます。前処理の一般的なアイデアは次のとおりです:
1、前処理識別の必要性を設定し、私は::デモを使用するなど、どのコードが前処理に行くために区別するために使用されます。
2、コードの必要性、エフェクト、共存するvueコード
3は、コードを取得し、直接v-preの内部に挿入の一部は、コンパイル用のcompileTemplateメソッドの内部に'@vue/component-compiler-utils'することができますし、対応するスロットにコンポーネントとして挿入されます。
これは言うほど複雑ではありませんが、実装はまだ少し複雑で、言うほど多くはありませんが、キーコードに直接
config.js内の設定
 plugins: [
 [require('./plugins/demo/')]
 ], 
プラグイン/デモ/index.js
/**
 *  ::: demo xxx ::: マークダウンでサンプルをビルドするための構文
 */
const path = require('path')
const renderDemoBlock = require('./render')
const demoBlockContainers = require('./containers')
module.exports = (options = {}, ctx) => {
 return {
 chainMarkdown(config) {
 config.plugin('containers')
 .use(demoBlockContainers(options))
 .end();
 },
 extendMarkdown: md => {
 const id = setInterval(() => {
 const render = md.render;
 if (typeof render.call(md, '') === 'object') {
 md.render = (...args) => {
 let result = render.call(md, ...args);
 const { template, script, style } = renderDemoBlock(result.html);
 result.html = template;
 result.dataBlockString = `${script}
${style}
${result.dataBlockString}`;
 return result;
 }
 clearInterval(id);
 }
 }, 10);
 }
 }
}
プラグイン/デモ/render.js
const {
 stripScript,
 stripStyle,
 stripTemplate,
 genInlineComponentText
} = require('./util.js');
module.exports = function (content) {
 if (!content) {
 return content
 }
 const startTag = '<!--pre-render-demo:';
 const startTagLen = startTag.length;
 const endTag = ':pre-render-demo-->';
 const endTagLen = endTag.length;
 let componenetsString = ''; // コンポーネント・リファレンス・コード
 let templateArr = []; // テンプレート出力
 let styleArr = []; // スタイル付き出力コンテンツ
 let id = 0; // demo のidは
 let start = 0; // 文字列の開始位置
 let commentStart = content.indexOf(startTag);
 let commentEnd = content.indexOf(endTag, commentStart + startTagLen);
 while (commentStart !== -1 && commentEnd !== -1) {
 templateArr.push(content.slice(start, commentStart));
 const commentContent = content.slice(commentStart + startTagLen, commentEnd);
 const html = stripTemplate(commentContent);
 const script = stripScript(commentContent);
 const style = stripStyle(commentContent);
 const demoComponentContent = genInlineComponentText(html, script); // サンプル・コンポーネント・コードの内容
 const demoComponentName = `render-demo-${id}`; // サンプルコード コンポーネント名
 templateArr.push(`<template><${demoComponentName} /></template>`);
 styleArr.push(style);
 componenetsString += `${JSON.stringify(demoComponentName)}: ${demoComponentContent},`;
 // 次の位置を再計算する
 id++;
 start = commentEnd + endTagLen;
 commentStart = content.indexOf(startTag, start);
 commentEnd = content.indexOf(endTag, commentStart + startTagLen);
 }
 // デモが存在しない場合のみ、Markdownでスクリプトタグを許可する。
 let pageScript = '';
 if (componenetsString) {
 pageScript = `<script>
 export default {
 name: 'component-doc',
 components: {
 ${componenetsString}
 }
 }
 </script>`;
 } else if (content.indexOf('<script>') === 0) {
 start = content.indexOf('</script>') + '</script>'.length;
 pageScript = content.slice(0, start);
 }
 // スタイル・コンテンツをマージする
 let styleString = '';
 if(styleArr && styleArr.length > 0) {
 styleString = `<style>${styleArr.join('')}</style>`
 } else {
 styleString = `<style></style>`
 }
 templateArr.push(content.slice(start));
 return {
 template: templateArr.join(''),
 script: pageScript,
 style: styleString
 }
};
plugins/demo/containers.js
const mdContainer = require('markdown-it-container');
module.exports = options => {
 const {
 component = 'demo-block'
 } = options;
 const componentName = component
 .replace(/^\S/, s => s.toLowerCase())
 .replace(/([A-Z])/g, "-$1").toLowerCase();
 return md => {
 md.use(mdContainer, 'demo', {
 validate(params) {
 return params.trim().match(/^demo\s*(.*)$/);
 },
 render(tokens, idx) {
 const m = tokens[idx].info.trim().match(/^demo\s*(.*)$/);
 if (tokens[idx].nesting === 1) {
 const description = m && m.length > 1 ? m[1] : '';
 const content = tokens[idx + 1].type === 'fence' ? tokens[idx + 1].content : '';
 const encodeOptionsStr = encodeURI(JSON.stringify(options));
 return `<${componentName} :options="JSON.parse(decodeURI('${encodeOptionsStr}'))">
 <template slot="demo"><!--pre-render-demo:${content}:pre-render-demo--></template>
 ${description ? `<div slot="description">${md.render(description).html}</div>` : ''}
 <template slot="source">
 `;
 }
 return `</template></${componentName}>`;
 }
 });
 };
}
プラグイン/デモ/util.js
const { compileTemplate } = require('@vue/component-compiler-utils');
const compiler = require('vue-template-compiler');
function stripScript(content) {
 const result = content.match(/<(script)>([\s\S]+)<\/\1>/);
 return result && result[2] ? result[2].trim() : '';
}
function stripStyle(content) {
 const result = content.match(/<(style)\s*>([\s\S]+)<\/\1>/);
 return result && result[2] ? result[2].trim() : '';
}
// 例を書くとき、テンプレートがあるとは限らないので、残りのコンテンツを除外することで解決する
function stripTemplate(content) {
 content = content.trim();
 if (!content) {
 return content;
 }
 return content.replace(/<(script|style)[\s\S]+<\/\1>/g, '').trim();
}
function pad(source) {
 return source
 .split(/
?
/)
 .map(line => ` ${line}`)
 .join('
');
}
function genInlineComponentText(template, script) {
 // https://.//-/////.#46
 const finalOptions = {
 source: `<div>${template}</div>`,
 filename: 'inline-component',
 compiler
 };
 const compiled = compileTemplate(finalOptions);
 // tips
 if (compiled.tips && compiled.tips.length) {
 compiled.tips.forEach(tip => {
 console.warn(tip);
 });
 }
 // errors
 if (compiled.errors && compiled.errors.length) {
 console.error(
 `
 Error compiling template:
${pad(compiled.source)}
` +
 compiled.errors.map(e => ` - ${e}`).join('
') +
 '
'
 );
 }
 let demoComponentContent = `
 ${compiled.code}
 `;
 
 script = script.trim();
 if (script) {
 script = script.replace(/export\s+default/, 'const democomponentExport =');
 } else {
 script = 'const democomponentExport = {}';
 }
 demoComponentContent = `(function() {
 ${demoComponentContent}
 ${script}
 return {
 render,
 staticRenderFns,
 ...democomponentExport
 }
 })()`;
 return demoComponentContent;
}
module.exports = {
 stripScript,
 stripStyle,
 stripTemplate,
 genInlineComponentText
};
効果をご覧ください:




