如何優雅的使用Vuepress編寫組件示例(下)👈

這是我參與8月更文挑戰的第2天,活動詳情查看:8月更文挑戰html

前言✍️

  • 最近在搭本身的組件庫,關於文檔用的是Vuepress
  • 官網在文檔說明展現組件示例的方法有不少種,但種種都不合心意
  • 經過查閱網上的資料和Element的源碼找出了我認爲的一種最優解,藉此機會分享一下
  • 該篇主要是具體的實現,若是想看分析的能夠看到如何優雅的使用Vuepress編寫組件示例(上)

實際效果✔️

先把最後的成品發出來給你們看看vue

image.png

李性分析🙋‍♂️

在上篇中分析概括了一下具體的步驟(以下),接下來咱們就來具體的實現一下webpack

  • 第一步構建一個通用組件用於接收代碼塊來展現demo而且統同樣式
  • 第二步設定一個Markdown自定義容器來編寫demo代碼
  • 第三步把自定義容器轉化成以前構建的通用組件,這樣就能夠在md使用自定義容器來實現上文效果
  • 第四步擴展markdown渲染方法使咱們輸入的代碼塊能夠輸出內容爲符合Vue Template語法的代碼塊
  • 第五步變成了vue代碼後交由Vuepressvue-loader處理編譯爲文檔

幹就完了👊

構建組件📦

docs
├─ .vuepress
│  ├─ components
│  │  └─ demoBlock.vue
│  ├─ config.js
│  └─ enhanceApp.js
└─ component
   └─ basic
      └─ button.md
複製代碼
  • 由於Vuepress能夠自動識別components裏面的組件並註冊因此咱們在裏面建一個通用組件demoBlock用於展現demo
  • 參考了Element的通用組件後觀察到這個組件主要由三部分組成:組件示例描述組件代碼塊
/* demoBlock.vue */
<template>
  <div class="block">
    <div class="demo-content">
      <!-- 插入組件 -->
      <slot name="demo"></slot>
    </div>
    <div class="meta" ref="meta">
      <div class="description">
        <!-- 插入描述信息 -->
        <slot name="description"></slot>
      </div>
      <div class="code-content">
        <!-- 插入代碼塊 -->
        <slot name="source"></slot>
      </div>
    </div>
  </div>
</template>
複製代碼
  • 以上是一個簡陋版的通用組件加上了簡陋的樣式,裏面包含了三個插槽分別是組件示例描述組件代碼塊,這樣咱們就能夠經過在mdvue的時候根據特別的插槽來組裝咱們的組件示例

建立自定義容器🧺

對於自定義組件咱們可使用markdown-it-container 參考官網構建git

/* containers.js */
const mdContainer = require('markdown-it-container');
module.exports =md => {
    //將markdown-it-container插件加載到當前的解析器實例中
    md.use(mdContainer, 'demo', {
      validate(params) {
        //函數在開始標記後驗證尾部,成功時返回true
        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] : '';
          // opening tag
          return `<demo-block>
                  <div slot="demo">組件demo</div>
                  <div slot="description">${description}</div>
                  <div slot="source">代碼塊</div>`
        } else {
          // closing tag
          return `</demo-block>`;
        }
      }
    });
  }
複製代碼

markdown-it-container支持兩個參數,第一個是自定義容器的名字,第二個是一些選項github

  • name - 自定義容器的名字
  • options:
    • validate - 可選,打開標記後驗證尾部的功能,true成功時應返回
    • render - 可選,用於打開/關閉標記的渲染器函數
    • marker - 可選 ( :),在分隔符中使用的字符

render方法中也有兩個參數web

  • tokens  (Array) -- token 們的列表
  • idx  (Number) -- 用來渲染的 token 的索引

值得一提的是token的兩個屬性npm

  • info  -- 三個反引號後面跟的那個字符串
  • nesting -- 標籤狀態: 1表示打開 0表示自動關閉 -1表示正在關閉

在選項中的render能夠對自定義的容器作渲染處理,像上面我就讓識別到demo的自定義容器渲染成這個格式,那麼咱們在md文件輸入自定義容器時就會找到對應的組件進行渲染api

建立完自定義容器後咱們要組裝到Vuepress的配置中,Vuepress自帶了chainMarkdown來修改內部的markdown配置,具體的配置操做能夠參考配置插件markdown

/* config.js */
module.exports = {
  title: 'Zylw-Ui',
  description: '開始你的組件化之旅吧~',
  ...
  plugins: [
    [
      require('./md-loader')
    ]
  ]
  ...
}
複製代碼
/* index.js */
const demoBlockContainers = require('./common/containers')
module.exports = () => {
  return {
    chainMarkdown(config) {
      //修改內部的 markdown 配置
      config // 增長額外的插件markdownContainers
        .plugin('markdownContainers')
        .use(demoBlockContainers)
        .end();
    }
  }
}
複製代碼

嘗試在md文件中使用後效果就出來了編輯器

image.png 此時的結構是這樣的

docs
├─ .vuepress
│  ├─ components
│  │  └─ demoBlock.vue
│  ├─ config.js
│  ├─ enhanceApp.js
│  └─ md-loader
│     ├─ common
│     │  └─ containers.js
│     └─ index.js
└─ component
   └─ basic
      └─ button.md
複製代碼

分別渲染💞

大致效果架子出來了以後,咱們就要考慮如何將自定義容器裏的內容分別輸出到組件位置代碼塊位置,一個典型的單文件組件包括三塊:template scriptstyle,那麼接下的重點就是如何拼湊出templatescript的內容

咱們能夠參考element的作法,因爲代碼太長,先放上Element的源碼能夠一塊兒食用 image.png 能夠看到Element在渲染的時候加入了一個佔位符來接受咱們的代碼塊,再經過編譯的時候對這個註釋塊進行處理就能夠分別轉化到template scriptstyle image.png

這時咱們就要改寫一下咱們的結構(此代碼靈感來自Demo Container

/* containers.js */
const mdContainer = require('markdown-it-container');
module.exports =md => {
    //將markdown-it-container插件加載到當前的解析器實例中
    md.use(mdContainer, 'demo', {
      validate(params) {
        //函數在開始標記後驗證尾部,成功時返回true
        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 : '';
          return `<demo-block>
            <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></demo-block>`;
      }
    })
  }
複製代碼
  • containers.js截取類型爲fence的代碼塊放到佔位符中
  • 經過render.js對佔位符的內容進行處理 具體代碼

image.png

image.png

  • 利用Vuepress的 extendMarkdown API 繼續拓展了其內部的markdown對象,修改內部用於渲染markdown文件的 markdown-it實例的配置
/* index.js */
const renderDemoBlock = require('./common/render')
module.exports = () => {
  return {
    ...
    extendMarkdown: md => {
      //修改內部用於渲染 markdown 文件的 markdown-it實例的配置
      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}\n${style}\n${result.dataBlockString}`;
            return result;
          }
          clearInterval(id);
        }
      }, 10);
    }
  }
}
複製代碼
  • 這樣一個簡陋的demo就大功告成啦!!!對比以前冗餘寫法是否是方便特別多呢,接下來只須要在demoBlock.vue更改屬於本身的樣式就能夠啦

image.png

docs
├─ .vuepress
│  ├─ components
│  │  └─ demoBlock.vue
│  ├─ config.js
│  ├─ enhanceApp.js
│  └─ md-loader
│     ├─ common
│     │  ├─ render.js
│     │  ├─ util.js
│     │  └─ containers.js
│     └─ index.js
└─ component
   └─ basic
      └─ button.md
複製代碼

寫在最後👋

  • 固然若是不想本身從新配一個自定義容器的話也是有現成的插件的Demo Container
  • 本文的分析思路靈感也是借鑑於這個插件,對於一些源碼的分析也是看了這位博主的插件才受益不淺
  • 總的來講組件示例的呈現方式有不少,可是目前爲止我以爲最好的是這種,經過markdown-it-container自定義容器的方法結合vue-template-compiler將代碼片斷轉換成組件,不一樣的文檔編輯器可能有不一樣的辦法但原理都是相同的要麼經過自身支持的插件進行配置要麼經過Webpack進行配置
  • 經過此次本身嘗試配置也深刻理解了一些markdownhtml的一些原理,因此仍是那句話多看源碼真的頗有用
  • 若是您以爲這篇文章有幫助到您的的話不妨🍉關注+點贊+收藏+評論+轉發🍉支持一下喲~~😛

參考👈

談談 Element 文檔中的 Markdown 解析

使用 markdown-it 解析 markdown 代碼

Demo Container插件

Vuepress文檔

Element UI

往期精彩🌅

Vue 3.0到底怎麼變快?🚀

如何優雅的使用Vuepress編寫組件示例(上)👈

手牽手🧑‍🤝‍🧑學習Gulp不用愁

爲了方便,我改了別人的輪子😅

相關文章
相關標籤/搜索