造輪子:寫vue組件庫orange-ui

項目搭建

項目效果地址

項目搭建參考 從零開始搭建 Vue 組件庫 VV-UI

項目地址

記錄模仿 VV-UI 組件庫造輪子中遇到的問題,以及解決方案

新建項目

對於腳手架環境的問題,目前已經有非常成熟的 vue 官方的腳手架,我們拿來用就好了

npm install vue-cli -g
vue init webpack origin-ui
cd origin-ui
npm install
npm run dev

項目可以正常啓動,在此基礎上進行改造

更改目錄

|-- examples            // 原 src 目錄,改成 examples 用作示例展示
  |-- assets            // api文檔logo 樣式文件
  |-- docs              // api文檔
  |-- router            // api文檔路由
|-- packages            // 新增 packages 用於編寫存放組件
  |-- button            // 組件
  |-- theme-default     // 組件樣式 gulp 運行目錄
  |-- lib               // 編譯後css
  |-- src               // 編譯前css
  |-- gulpfile.js       // gulp 寫打包css的task
  |-- salad.config.json // BEM的配置文件
  |-- index.js          // 導出組件

原 src 目錄,改成 examples 用作示例展示,需要對應修改 webpack 配置

把原先的編譯指向 src 的目錄改成 examples

{
  test: /\.(js|vue)$/,
  loader: 'eslint-loader',
  include: [resolve('examples'), resolve('test'), resolve('packages')],// 修改
}
entry: {
  app: './examples/main.js' // 程序入口修改
},
resolve: {
  alias: {
    vue$: 'vue/dist/vue.esm.js',
    '@': resolve('examples') // 根據實際情況修改
  }
},

如何編寫文檔

使用vue-markdown-loader在 vue 下可以去寫 markdown 文檔

安裝

# For Vue2
npm i vue-markdown-loader -D
npm i  vue-loader vue-template-compiler -D

使用

webpack.config.js file:

module.exports = {
  module: {
    rules: [
      {
        test: /\.md$/,
        loader: 'vue-markdown-loader'
      }
    ]
  }
}

在 example/docs 目錄下新建 test.md

同時創建一個新的路由,指向我們的 md 文件:

{
  path: '/test',
  name: 'test',
  component: r => require.ensure([], () => r(requi('../docs/test.md')))
}

打開瀏覽器訪問http://localhost:8080/#/test

實現 demo/代碼演示

  • 需求 1 就是攔截 import,並且解析 markdowm 語法
  • 需求 2 在析 markdown 中也可以寫 Vue 的組件

全部配置可參考Vue 加載 Markdown 格式組件有詳細註釋

markdown-it,支持 options 選項。這樣我們就可以爲我們的 markdown 定義獨特的標識符,這裏我用 demo 標識需要顯示代碼塊的地方,所以我需要配置 options 選項 :

const vueMarkdown = {
  preprocess: (MarkdownIt, source) => {
    MarkdownIt.renderer.rules.table_open = function() {
      return '<table class="table">'
    }
    MarkdownIt.renderer.rules.fence = utils.wrapCustomClass(
      MarkdownIt.renderer.rules.fence
    )
    return source
  },
  use: [
    [
      MarkdownItContainer,
      'demo',
      {
        // 用於校驗包含demo的代碼塊
        validate: params => params.trim().match(/^demo\s*(.*)$/),
        render: function(tokens, idx) {
          var m = tokens[idx].info.trim().match(/^demo\s*(.*)$/)

          if (tokens[idx].nesting === 1) {
            var desc = tokens[idx + 2].content
            // 編譯成html
            const html = utils.convertHtml(
              striptags(tokens[idx + 1].content, 'script')
            )
            // 移除描述,防止被添加到代碼塊
            tokens[idx + 2].children = []

            return `<demo-block>
                        <div slot="desc">${html}</div>
                        <div slot="highlight">`
          }
          return '</div></demo-block>\n'
        }
      }
    ]
  ]
}

這裏簡單的描述一下這段代碼是幹什麼的:首先把內容裏面 vue 片段編譯成 html,用於顯示,另一方面用 highlight 來高亮代碼塊。demo-block 本身是我們定義好的組件:

<template>
  <div class="docs-demo-wrapper">
    <div :style="{maxHeight: isExpand ? '700px' : '0'}" class="demo-container">
      <div span="14">
        <div class="docs-demo docs-demo--expand">
          <div class="highlight-wrapper">
            <slot name="highlight"></slot>
          </div>
        </div>
      </div>
    </div>
    <span class="docs-trans docs-demo__triangle" @click="toggle"
      >{{isExpand ? '隱藏代碼' : '顯示代碼'}}</span
    >
  </div>
</template>

基本用法:

::: demo
<o-button>默認按鈕</o-button>
:::

如何編寫組件

環境準備完畢,緊接着要開始編寫組件,考慮的是組件庫,所以我們竟可能讓我們的組件支持全局引入和按需引入,如果全局引入,那麼所有的組件需要要註冊到 Vue component 上,並導出:

const install = function(Vue) {
  if (install.installed) return
  components.map(component => Vue.component(component.name, component))
}

export default {
  install
}

着要實現按需加載,我們只需要單個導出組件即可:

import Button from './button/index.js'
import Row from './row/index'
import Col from './col/index'

const components = [Button, Row, Col]

const install = function(Vue) {
  if (install.installed) return
  components.map(component => Vue.component(component.name, component))
}

if (typeof window !== 'undefined' && window.Vue) {
  install(window.Vue)
}

export { install, Button, Row, Col }

既然是單頁面應用,必然要去解決樣式衝突問題,如果組件內使用 soped,那麼樣式就無法從組件內抽離出來,達不到可定製化主題顏色的目的。我們需要一套可以分離處理的樣式,可以自行編譯,可以相互不污染。這時候 css 的 BEM 規範就顯得尤爲重要。如果你還不知道什麼是 BEM 參考: http://www.w3cplus.com/css/cs...
說到這裏,目前對 BEM 規範支持較好的插件就是 postcss 了,他允許我們配置 BEM 之間的連接符和縮寫:

{
  "browsers": ["ie > 8", "last 2 versions"],
  "features": {
    "bem": {
      "shortcuts": {
        "component": "b",
        "modifier": "m",
        "descendent": "e"
      },
      "separators": {
        "descendent": "__",
        "modifier": "--"
      }
    }
  }
}

這樣我們就可以把樣式單獨的抽離出來,通過 gulp 進行打包編譯:

gulp.task('compile', function() {
  return gulp
    .src('./src/*.css')
    .pipe(postcss([salad]))
    .pipe(cssmin())
    .pipe(gulp.dest('./lib'))
})

關於 gulp 的使用

npm install --global gulp
npm install --save-dev gulp

進入 packages/theme-default 中,運行 gulp

gulp
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章