【Vue進階】青銅選手,如何自研一套UI庫?

前言

更新javascript

  1. 本地跑ange-ui項目的時候須要全局安裝vuepress,目前vuepress有0.x和1.x版本(剛發佈,查看1.x文檔)系列,安裝最新的vupress沒法正常運行項目(感謝 @_嗚啦啦啦火車笛 提出),本項目使用1.x vuepress會有如下問題:
  • 受權拒絕錯誤
  • 與最新版sas-loader(7.x)不兼容
  1. 使用0.x能夠避免npm install vuepress@0.14.11 -g 幾天前官方發佈的vuepress 1.x版本:

謝謝你們支持!css

即使是一個青銅,也要用王者的心去編碼!html

output

Github上關於Vue的UI庫,大大小小不可勝數,即使是已經被推廣使用的成熟庫,也有不少。不少時候,咱們自研一套UI庫,不是想要作得多牛逼,競爭過別人(事實咱也幹不過人家,除非你不是一我的在戰鬥。畢竟這不只是個技術活,仍是個體力活),咱們僅僅是源自一個青銅對王者的仰望或者是爲知足心裏的需求。vue

這裏跟你們講一個一步一步自研UI庫的故事。java

原文地址:github.com/qiud...node

項目地址:Ange UIwebpack

開發一套UI庫,作成不難(這裏指的是半半半成品,全品也好難。。。),作好很難。但不慌,咱有祕籍css3

  1. 必定的內功修爲。所謂打鐵還需自身硬,要作高複用組件的開發工做,對Vue.jsCSS3仍是有必定的技術要求。那我要多牛逼才能寫好這個UI庫啊?這取決於你這套UI庫的實現高度。
  2. 一些招式套路。藏經閣(Github)上有不少關於Vue的UI庫:六脈神劍、獨孤九劍應有盡有。人家怎麼寫的,我們跟着來就行了。有人可能意見很大,那不是在模仿嗎?這裏要嚴正聲明,咱們不是在模仿,咱們只是向標準靠攏。由於牛逼的就是標準的

UI庫的必要架構

一套成熟的開源UI庫通常都具有如下幾個特色:git

  • 包含了組件源碼
  • 完備的說明文檔
  • 符合Eslint校驗標準
  • 全面的單元測試
  • 完整的構建生態

所以,它們的目錄架構也出現了主要的兩種形式: github

image
&
image
有點大同小異,這裏咱們按照第一種架構去開發。

  • build:存放構建配置文件
  • docs:官方說明文檔
  • src:組件源碼
  • test:單元測試用例(這裏不做闡述)
  • eslintrc:基於eslint-plugin-vue的開發規範標準

搭建UI開發環境

觀察社區幾大UI庫發現,它們都是基於webpack搭建了本身的構建配置,包括本地開發、生產環境構建、UI庫的打包等,創建一套本身的構建生態。咱們就不一樣了,業餘一點(實際上是善於應用開源工具),咱們的docs文檔是基於vuepress的,vuepress有本身一套的構建體系,因此咱們只須要針對UI組件源碼寫一份打包配置就行了。

下面開始搭建打包配置(其實就是好久之前咱們作的基於webpack的構建,如今cli用得多了,配置也不會寫了,碼耶): 首先在根目錄創建configbuild文件夾,而後往兩個目錄分別新建文件,以下:

image

  • build-lib.js:node執行的腳本,讀取並執行lib的配置進行構建;
  • webpack.base.conf.js:公共的構建配置;
  • webpack.lib.conf.js:針對UI組件打包的配置;
  • index.js:可變的配置信息;
  • prod.env.js:聲明當前構建環境爲生產環境的配置;

不是說只有一份打包的配置文件麼?咋還多了那麼多文件呢?是這樣,雖然咱們是業餘的,但咱也想作得專業一點對吧(有利於對配置進行擴展管理)!

咱們看 config/index.js有什麼?

image
好像註釋也很清楚?這些定義最終都被應用在 webpack.lib.conf.js中。

再看看build/webpack.base.conf.js裏面的關鍵配置:

image
基礎配置裏面的 entryoutput會被 webpack.lib.conf.js覆寫; rules定義一系列loader的轉換規則,其中eslint的校驗就是在這裏定義了一個 eslint-loader

最後看一眼build/webpack.lib.conf.js配置:

image
lib裏面重寫 entry的規則是,根據傳參值(components)分別走不一樣的入口文件,一種只有一個 ./src/index.js,這個是UI對外註冊的入口文件(這使得咱們能夠引入整個UI);另外一種是各個UI組件的註冊入口文件(這使得咱們能夠按需引入組件);

先給你們貼圖直觀感覺下源碼的目錄結構:

image

那實際打包的時候走的是哪種呢?真相是都走!在build-lib.js中,執行了三次打包,打包輸出效果以下:

image
第一次的打包的輸出是通過壓縮的(壓縮css樣式表文件,能夠看到輸出文件帶了min後綴),第二次是未壓縮的,最後一次是對各組件分別打包。(PS:我很想給你們用紅圈圈在圖上標記下,奈何設備不容許。。。數度哽咽......Ubuntu系統下你們有好用的截圖標記工具能夠推薦下嗎?)

開發一個組件

前面紮好了馬步,終於到修煉招式的階段了! 咱們都知道,在應用某個插件的時候須要通過下面代碼的調用:

import Ange from 'ange-ui'
Vue.use(Ange)
複製代碼

好奇下Vue.use在作什麼處理呢?它其實就是註冊/安裝這個插件,根據use內部的定義,它經過調用install方法去註冊插件,那麼,Ange就必須是一個Function(會被use當作是install方法調用)或者是一個包含了install方法的Object

道理我都懂,但是install方法裏面到底寫些什麼?

試想一下,咱們但願在項目的任意位置都能引用這個插件,那咱們的每個組件是否是要在全局註冊?好比經過下面這種方式全局註冊組件:

Vue.component('pagination', pagination)
複製代碼

沒錯,install方法內部就是批量地全局註冊組件。

搭好目錄架構

首先咱們按照下圖的方式新建目錄和文件:

image
src目錄的index.js文件中定義 install方法:

import './scss/ange.scss'  // 引入組件樣式表,也可讓用戶在使用的時候自行引入
import components from './components'

function install(Vue, opts = {}) {
    Object.values(components).forEach((each) => {
        Vue.component(each.name, each)
    })
}

if (typeof window !== 'undefined' && window.Vue) {
    install(window.Vue)
}
export default {
    version: '1.0.0',
    install,
    ...components
}
複製代碼

核心邏輯install就是對全部的組件循環註冊在全局。components目錄的 index.js 則是逐個對外暴露組件對象,其次每個組件也有一個 index.js ,它的做用是爲當前組件注入install方法。理所固然地,install裏面是將該組件註冊在全局,因而咱們能夠按需引用組件。

開發Button組件

組件開發的通用模板

<template>
    <component :is="'button'"></component>
</template>

<script>
export default {
    name: 'ag-button',
    props: {}
}
</script>
複製代碼

component是vue的內置組件,is參數設置成button,代表最終渲染的html是button標籤,咱們也能夠直接使用button標籤,但咱們的按鈕組件不必定是button,還多是a標籤,爲了更好的拓展,這裏使用component。

聲明組件參數

export default {
    name: 'ag-button',
    props: {
        // 按鈕類別
        primary: Boolean,
        secondary: Boolean,
        dashed: Boolean,
        link: Boolean,
        // 按鈕狀態
        color: {
            type: String,
            validator (val) {
                return new Set(['success', 'warn', 'danger']).has(val)
            }
        },
        // 按鈕尺寸
        size: {
            type: String,
            validator (val) {
                return new Set(['large', 'normal', 'small']).has(val)
            }
        },
        // 圖標按鈕
        icon: String,
        // 圓形按鈕(通常結合圖標按鈕使用)
        circle: Boolean,
        // 外鏈按鈕
        external: Boolean,
        // 異步按鈕
        loading: Boolean
    }
}
複製代碼

完善組件模板

<template>
    <component :is="tag" class="ange-btn" :class="[ btnSize, color, { 'default': isDefault, 'primary': primary, 'secondary': secondary, 'dashed': dashed, 'link': link, 'icon': icon, 'circle': circle }]" @click="$emit('click', $event)" :disabled="loading">
        <span class="ange-btn-content">
            <!-- 圖標按鈕依賴 ag-icon 組件 -->
            <ag-icon v-if="icon" :icon="icon" />
            <slot />  <!-- 插槽接收按鈕文本 -->
        </span>
    </component>
</template>

<script> export default { // ... computed: { tag () { return this.external ? 'a' : 'button' }, isDefault() { const type = [this.primary, this.secondary, this.dashed, this.link] return type.every((each) => !each) }, btnSize() { return this.size || 'normal' } } } </script>

複製代碼

剩下的工做就是寫好樣式表了,你能夠選擇直接寫在vue文件裏面,也能夠新建_scss/scss_樣式表。

組件應用及效果在線查看

image

以上,便開發好一個button組件了,執行一下node build-lib.js或者npm run build:lib(如今package.json聲明script)就能夠打包這個UI框架,而後再將其發佈到npm平臺(若是你想...)

寫好一份文檔

在線查看 Ange UI Docs 寫好文檔是一個庫不可或缺的部分,寫的過程經過實際應用各組件,還能夠對其進行測試校驗。前面說到,咱們的文檔要基於vuepress開發,簡潔的Markdown寫法,非常方便。這裏一篇 指南 能夠很好地幫助你,它告訴了你如何搭建架構,寫好配置以及部署上線,或者參考我這個 倉庫 的配置。

假設docs/views/button.md是你的button組件的文檔頁面,要如何引用你的組件?

image
Ange UI內置引入了樣式表,這裏能夠不用再引入,也能夠按需只引入 button組件:

import '@scss/ange.scss'
import Button from '@component/button'
Vue.use(Button)
複製代碼

至此,文檔也就寫好了!

最後的最後,按照 vuepress doc 部署到你的github倉庫上就能夠了!

本文經過button組件從0到1的開發,深刻淺出闡述了Vue UI框架的開發流程,你對Vue.js的理解越深,組件的功能越複雜,你就會用到更多的高級用法。經過自研UI框架,咱們也有很大的收穫:

  • 從新溫習webpack配置
  • 深刻理解Vue內部機制,掌握更多的vue高級用法
  • 夯實js和css3基礎
  • 掌握編程範式和設計模式

PS:CSS實際上是UI開發中佔比很重的部分,你們按照本身的風格組件化開發就好。給你們推薦幾個很棒的配色網站

最後,但願你們也能多多去嘗試,這個青銅自研UI庫的故事到這裏就結束了。

The end.

相關文章
相關標籤/搜索