elementui源码解析markdown处理

摘要:
m[1]:'';//紧跟在demo后面的描述的内容constcontent=tokens[idx+1].type==='fence'?tokens[idx+1].content:'';//html的匹配内容//返回把内容放到已经写好的组件demo-block里;把html的内容放到!--element-demo里,便于后面处理抽取//demo-block组件已经是在entry.js里作为全局组件注册过了可以直接使用return`${description?--element-demo:${content}:element-demo--˃`;}return'';}});md.use;md.use;};在build/md-loader/index.js里处理解析放入到˂!--element-demo里,在这里做提取处理cons

一些参考网址:

markdown-it插件的分析和源码分析参考地址:https://zhuanlan.zhihu.com/p/64290806
element-ui的源码地址:https://github.com/ElemeFE/element

一:先从package.json找到本地运行官网的指令是在scripts里的dev指令

"dev": "npm run build:file && cross-env NODE_ENV=development webpack-dev-server --config build/webpack.demo.js & node build/bin/template.js",

找到对应md解析的module的处理loader

elementui源码解析markdown处理第1张处理markdown文件是先用build/md-loader/index.js处理了,然后再用vue-loader处理的;

md组件文件都在 examples/docs里,下面拿examples/docs/zh-cn/button.md组件的解析为例子

二: 进入build/md-loader/index.js里查看时如何解析的md文件的

//build/md-loader/index.js
const {
  stripScript,
  stripTemplate,
  genInlineComponentText
} = require('./util'); //提取script内容和纯内容部分,以及拼接好模板的方法
const md = require('./config'); //暴露出已经处理好markdownit插件的md
module.exports = function(source) {
  const content = md.render(source); //config里对render的插件的处理
...
};

第一步是在build/md-loader/config.js里处理的

// build/md-loader/config.js
const Config = require('markdown-it-chain'); //支持链式调用 markdown-it const anchorPlugin = require('markdown-it-anchor'); //配置标题目录跳转的插件 const slugify = require('transliteration').slugify; //把中文翻译成拼音的插件 const containers = require('./containers'); //内容块容器化处理插件 const overWriteFenceRule = require('./fence'); //修改默认的fence规则的渲染函数,加上展开的源码的部分 const config = newConfig(); config .options.html(true).end() .plugin('anchor').use(anchorPlugin, [ { level: 2, slugify: slugify, permalink: true, permalinkBefore: true} ]).end() .plugin('containers').use(containers).end(); //主要是这个插件里处理md里写的elementui组件的渲染的代码 const md =config.toMd(); overWriteFenceRule(md); module.exports = md;

主要的md里编写的elementui组件处理插件是build/md-loader/containers.js里处理的,把:::demo 和 ::: 之间的非描述部分,放到了<!--element-demo: ${content}:element-demo-->,后面在build/md-loader/index.js里处理;

// build/md-loader/containers.js
const mdContainer = require('markdown-it-container'); //这个插件可以让你支持内容块,识别 markdown的::: module.exports = md =>{ //用在markdown-it里,识别 ::: demo md.use(mdContainer, 'demo', { validate(params) { return params.trim().match(/^demo\s*(.*)$/); //*是匹配0次以上 }, /** * tokens 符合上面规则的所有内容 * idx 某一条的id */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] : ''; //紧跟在demo后面的描述的内容 const content = tokens[idx + 1].type === 'fence' ? tokens[idx + 1].content : ''; //html的匹配内容 //返回把内容放到已经写好的组件demo-block里;把html的内容放到!--element-demo里,便于后面处理抽取 //demo-block组件已经是在entry.js里作为全局组件注册过了可以直接使用 return `<demo-block>${description ? `<div>${md.render(description)}</div>` : ''} <!--element-demo: ${content}:element-demo-->`; } return '</demo-block>'; } }); md.use(mdContainer, 'tip'); md.use(mdContainer, 'warning'); };

在build/md-loader/index.js 里处理解析放入到<!--element-demo: ${content}:element-demo--> 里的内容,提取里面的template部分和script部分,放到

<section class="content element-doc"> 里;
//build/md-loader/index.js
const {
  stripScript,
  stripTemplate,
  genInlineComponentText
} = require('./util');
const md = require('./config'); //暴露出已经处理好markdownit插件的md
module.exports = function(source) {
  const content =md.render(source);

  //md插件对里面的内容放到了<!--element-demo里,在这里做提取处理
  const startTag = '<!--element-demo:';
  const startTagLen =startTag.length;
  const endTag = ':element-demo-->';
  const endTagLen =endTag.length;

  let componenetsString = '';
  let id = 0; //demo 的 id
  let output = []; //输出的内容
  let start = 0; //字符串开始位置
let commentStart = content.indexOf(startTag); //html开始的下标值
  let commentEnd = content.indexOf(endTag, commentStart + startTagLen); //html结束的位置,从开始的标识结束的后面计算
  //循环处理html的内容,必须是有开始和结尾标识的
  while (commentStart !== -1 && commentEnd !== -1) {
    output.push(content.slice(start, commentStart)); //拿到前面非html内容的描述等文字部分
const commentContent = content.slice(commentStart + startTagLen, commentEnd); //拿到除去前后标识的html内容部分
    const html = stripTemplate(commentContent); //拿到非script和style的内容部分
    const script = stripScript(commentContent); //拿到script部分
    let demoComponentContent = genInlineComponentText(html, script); //把md提取的内容拼接成vue的template编译的js
    const demoComponentName = `element-demo${id}`;
    output.push(`<template slot="source"><${demoComponentName} /></template>`); //把内容放到demo-block的source的slot中
    componenetsString += `${JSON.stringify(demoComponentName)}: ${demoComponentContent},`; //把处理好的template都作为组件放到components里

    //重新计算下一次的位置
    id++;
    start = commentEnd +endTagLen;
    commentStart =content.indexOf(startTag, start);
    commentEnd = content.indexOf(endTag, commentStart +startTagLen);
  }

  //仅允许在 demo 不存在时,才可以在 Markdown 中写 script 标签
// componentsString是在上面提取的所有的 组件demo作为组件拼接的字符串
//todo: 优化这段逻辑 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); } output.push(content.slice(start)); return` <template> <section class="content element-doc">${output.join('')} </section> </template> ${pageScript} `; };

在 build/md-loader/fence.js里重写md.renderer.rules.fence 规则,把md里的elementui组件放大demo-block的highlight插槽里,用于展示组件源码;

//覆盖默认的 fence 渲染策略
module.exports = md =>{
  const defaultRender =md.renderer.rules.fence;
  md.renderer.rules.fence = (tokens, idx, options, env, self) =>{
    const token =tokens[idx];
    //判断该 fence 是否在 :::demo 内
    const prevToken = tokens[idx - 1];
    const isInDemoContainer = prevToken && prevToken.nesting === 1 && prevToken.info.trim().match(/^demo\s*(.*)$/);
    if (token.info === 'html' &&isInDemoContainer) {
      //html的加上高亮标签
      return `<template slot="highlight"><pre v-pre><code class="html">${md.utils.escapeHtml(token.content)}</code></pre></template>`;
}
    returndefaultRender(tokens, idx, options, env, self);
  };
};

全局组件demo-block的组件展示和组件源码插槽代码如下:

// examples/components/demo-block.vue
<
template> <div class="demo-block":class="[blockClass, { 'hover': hovering }]"@mouseenter="hovering = true"@mouseleave="hovering = false"> <div class="source"> <!--组件渲染展示的位置 --> <slot name="source"></slot> </div> <div class="meta"ref="meta"> <div class="description"v-if="$slots.default"> <slot></slot> </div> <div class="highlight"> <!--组件源码展示的位置 --> <slot name="highlight"></slot> </div> </div> <div 。。。。

免责声明:文章转载自《elementui源码解析markdown处理》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇简单应用复旦FNLP自然语言处理工具(一)超详细简单小白安装GIT教程下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

python嵌入C++ boost.python如何在C++中调用含有不定长参数tuple变量和关键字参数dict变量的函数

    这个问题是在我尝试利用pygraphviz嵌入我的C++代码绘制二叉树的时候发现的.找了半天资料,这里我把几种常用的C++调用 PYTHON利用 boost.python 的方法作一个总结,希望能让别人少走弯路,因为有些内容还找不到中文文档,虽然都不难但是开始摸索 还是费时间的.     我个人认为boost.python真的是非常的COOL,基...

WinForm 创建与读写配置文件

1. 创建 app.config 文件:右击项目名称,选择“添加”→“添加新建项”,在出现的“添加新项”对话框中,选择“添加应用程序配置文件”;如果项目以前没有配置文件,则默认的文件名称为“app.config”,单击“确定”。 出现在设计器视图中的app.config文件为: <?xml version="1.0" encoding="utf...

vue 中使用 axios 封装及使用

一, 配置BaseUrl /** * { * dev: '开发环境配置信息', * test: '测试环境配置信息', * prod: '线上环境配置信息' * } */ function conf (base = {}) { if (process.env.NODE_ENV === 'production' || proces...

[持续集成]Jenkins 自动化部署 Maven 工程

一、Jenkins 持续部署原理图 基础服务: 1 SVN 服务      SVN是Subversion的简称,是一个开放源代码的版本控制系统。说得简单一点SVN就是用于多个人共同开发同一个项目,共用资源的目的。(源自百度百科) 2 Nexus 服务      Maven的一种仓库软件。 3 Jenkins服务      持续集成工具。 4 Web容器服...

HTML页面过渡效果大全

IE要求:  在IE5.5及以上版本的浏览器中.启用网页过渡效果  默认情况下都已经启用了,如果需要手动启用则只需在Internet选项中: Advanced(高级) - Browsing(浏览) - Enable page transitions(启用页面过渡)即可。应用过渡效果  当我们需要添加过渡效果时,只需在<head>中添加一个特殊的...

log.io日志实时显示

Node.js 安装 菜鸟教程Node.js安装 设置 npm 淘宝镜像 npm config set registry https://registry.npm.taobao.org npm config get registry log.io 简介 官网地址github地址 安装服务端 npm install -g log.io 配置服务端 找...