現在前端工程師的要求愈來愈高了,須要掌握的技術點愈來愈多了,會一些基本的前端技能徹底適應不了快速變化的前端領域了。接下來我將從零實現一個本身的UI組件庫併發布到npm上,提供給須要的朋友參考也總結下本身對封裝組件的理解方便之後複習。html
本項目以button
按鈕爲例,詳細的記錄一下封裝一個Button UI組件每個步驟以及須要注意的地方:前端
檢查 node 環境配置
先本地全局安裝node環境,vue的運行是依賴於node
的npm
的管理工具來實現的,node下載地址。下載好node以後,打開cmd管理工具,輸入node -v
,回車,查看node版本號,出現版本號則說明安裝成功,注意:node 的版本要在 8.9 或更高版本 (推薦 8.11.0+)vue
node -v npm -v
Vue 版本
若是你已經全局安裝了舊版本的 vue-cli (1.x 或 2.x),你須要先經過 npm uninstall vue-cli -g 或 yarn global remove vue-cli 卸載它, Vue CLI 的包名稱由 vue-cli 改爲了 @vue/cli。node
npm install -g @vue/cli # OR yarn global add @vue/cli
vue --version | vue -V
建立項目
vue create mc-ui OR vue ui 也可使用UI圖形化界面建立項目
注意:因爲咱們是開發一個第三方依賴庫,咱們選擇 Manually select features。webpack
(*) Babel ( ) TypeScript ( ) Progressive Web App (PWA) Support ( ) Router ( ) Vuex (*) CSS Pre-processors (*) Linter / Formatter ( ) Unit Testing ( ) E2E Testing
系統默認的包含了基本的 Babel + ESLint 設置的 preset,咱們只須要選擇CSS配置。移動鍵盤上下鍵選擇須要的特性,按下鍵盤空格鍵便可選中git
Sass/SCSS (with dart-sass) Sass/SCSS (with node-sass) Less Stylus
因爲Element UI中的樣式採用Sass,因此咱們選擇第一項便可
爲何不選擇第二項呢?
由於dart-sass比node-sass更好下載github
ESLint with error prevention only ESLint + Airbnb config ESLint + Standard config ESLint + Prettier
因我的喜愛選擇便可,我比較喜歡第三種web
(*) Lint on save ( ) Lint and fix on commit
選擇Ctrl+S保存時檢測代碼格式便可面試
In dedicated config files In package.json
因我的喜愛,我比較喜歡選擇第二種vue-cli
Save this as a preset for future projects? (y/N)
看項目須要,我這裏選擇 N。回車後,系統會自動幫咱們把選擇的配置集成到模板中,而後生成一個完整的項目。
咱們大體按照Element UI的 源碼 目錄進行咱們本身的UI庫項目開發。因此刪除系統自動爲咱們建立的src、assets等目錄,在根目錄中建立一個packages目錄用來存放咱們要開發的UI組件;在根目錄建立一個test目錄用於測試咱們本身開發的UI組件。
因爲咱們更改了原項目的目錄結構,使得系統本地運行以及打包找不到對應的目錄,咱們須要在項目的根目錄中建立一個vue.config.js文件夾手動的去修改webpack配置,使得系統本地運行和打包正常。
// vue.config.js const path = require('path'); module.exports = { pages: { index: { entry: 'test/main.js', template: 'public/index.html', filename: 'index.html' } }, chainWebpack: config => { config.module .rule('js') .include.add(path.resolve(__dirname, 'packages')).end() .use('babel') .loader('babel-loader') .tap(options => { return options; }) } }
<mc-botton class="mc-bottom"></mc-botton>
的實現<template>
<template> <button class="mc-button"> <span> <slot></slot> // slot表示插槽 </span> </button> </template>
注意:爲何要在slot插槽外面加個span標籤呢?爲了美觀,每一個自定義button組件間相互有點間距🤭
<script>
export default { name: 'McButton' }
注意:組件中填寫name屬性,是爲了封裝組件提供install方法時,動態獲取每一個組件名進行組件註冊
<style>
.mc-button { box-sizing: border-box; outline: none; margin: 0; transition: 0.1s; font-weight: 500; -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none; .... }
注意:user-select屬於CSS3的屬性,值爲none表示禁止用戶選中文字
<mc-botton type="xxx" class="mc-bottom"></mc-botton>
的實現常見的類型有:primary / success / warning / danger / info / text
<template>
<button class="mc-button" :class="[ `mc-button--${type}` ]"> ... </button>
注意:爲何綁定class時採用數組形式,而不用對象形式,由於會有多個動態綁定的屬性,且使用對象的形式,這樣就只有數組裏能夠放多個動態屬性,且屬性能夠爲對象
<script>
props: { type: { type: String, default: 'default' } }
注意:這裏接收屬性爲何不用數組的形式?由於咱們是封裝組件給別人用的,因此要限制一些條件,不能讓用戶隨意的輸入
<style>
該功能時,樣式沒有改動
<mc-botton plain class="mc-bottom"></mc-botton>
的實現<template>
<button class="mc-button" :class="[ `mc-button--${type}`, { 'is-plain': plain } ]"> ... </button>
注意:爲何綁定class時採用數組形式,而不用對象形式,由於會有多個動態綁定的屬性,且使用對象的形式,這樣就只有數組裏能夠放多個動態屬性,且屬性能夠爲對象
<script>
plain: { type: Boolean, default: false }
<style>
&.is-plain:hover, &.is-plain:focus { background: #fff; border-color: #409eff; color: #409eff; }
<mc-botton round class="mc-bottom"></mc-botton>
的實現<template>
<button class="mc-button" :class="[ `mc-button--${type}`, { ... 'is-round': round } ]"> ... </button>
<script>
round: { type: Boolean, default: false }
<style>
&.is-round { border-radius: 20px; padding: 12px 23px; }
<mc-botton class="mc-bottom is-circle"></mc-botton>
的實現<template>
<button class="mc-button" :class="[ `mc-button--${type}`, { ... 'is-circle': circle } ]"> ... </button>
<script>
circle: { type: Boolean, default: false }
<style>
&.is-circle { border-radius: 50%; padding: 12px; }
<mc-botton class="mc-bottom" disabled></mc-botton>
的實現<template>
<button ... :disabled="disabled" :class="[ `mc-button--${type}`, { ... 'is-disabled': disabled } ]"> ... </button>
<script>
disabled: { type: Boolean, default: false }
注意:添加是否被禁用時有兩個做用:第1、讓用戶不能點擊;第2、改變按鈕樣式
<mc-botton icon="el-icon-check" class="mc-bottom"></mc-botton>
的實現<template>
<button ... > <i :class="icon" v-if="icon"></i> <!-- 若是沒有傳入插槽的時候才顯示 --> <span v-if="$slots.default"><slot></slot></span> </button>
<script>
icon: { type: String, default: '' }
<style>
.mc-button [class*=mc-icon-]+span { margin-left: 5px; }
i標籤上加v-if的目的:讓用戶便可以上傳圖標也能夠上傳文字或者上傳文字和圖標
注意:既傳圖標也傳文字的話,圖標和文字隔的很近,咱們須要特殊處理下; 可是若是特性處理的話,單獨的圖標會不居中顯示;因此咱們要使用$slots獲取包含有插槽的才讓其顯示處理
<mc-botton class="mc-bottom" @click="handleClick"></mc-botton>
的實現<template>
<button ... @click="handleClick" > ... </button>
<script>
methods: { handleClick (e) { this.$emit('click', e) // 向父組件派發一個click事件,e表示攜帶的參數 } }
在Vue-cli3的 官方文檔 中有個構建目標
有明確的說明怎麼打包成一個應用或者一個庫!此時,咱們須要在package.json中添加一條打包命令
vue-cli-service build --target lib 指定打包的文件
而後控制檯執行yarn lib
便可將咱們的組件庫包括字體圖標一塊兒打包生成一個dist文件夾
將代碼上傳到github
首先登陸github 官網 建立一個新的倉庫,而後複製新倉庫的git地址。 而後在咱們本地建立的項目根目錄執行git init,初始化git,而後再終端執行如下命令:
git remote add origin git add . git commit -am ":rocket: project init" git push -u origin master
你們有沒有發現我提交的commit不同,其實就是用到了gitmoji這個依賴而已,簡單說下他的用法:
將代碼發佈到npm
因爲咱們開發的組件庫是給別人用的,咱們沒有必要把全部的代碼都發布到npm上。因此咱們須要在項目的根目錄建立一個.npmignore的文件,忽略那些文件上傳
// .npmignore # 忽略目錄 test/ packages/ public/ # 忽略指定文件 vue.config.js babel.config.js *.map .editorconfig.js
注意:因爲咱們要上傳到npm上,因此咱們本地npm的源要使用npm的源,不能使用淘寶源或其餘的。
查看一下本地電腦全部的源:
一切準備工做作好後,打開終端,執行npm login進行登陸
執行npm login命令,系統會提示輸入帳戶和密碼。若是沒有npm帳戶,請註冊 → npm官網
若帳戶登陸成功後,就能夠再次執行 npm publish 進行發佈
vue 版的git地址:https://github.com/tangmengcheng/mc-ui.git vue + ts 版的git 地址:https://github.com/tangmengcheng/ts-ui.git 若是對須要的小夥伴有幫助,歡迎小夥伴們點贊、評論加關注!🤭star~~~
相信只要從頭看到尾的小夥伴就會發現,封裝一個組件很容易,主要的工做在於CSS樣式上。只要本身有時間,而後根據像Element、iView、Antd等優秀的第三方UI庫的源碼,也能夠實現一套屬於本身的UI庫。不論是面試仍是本身公司內部須要搭建本身的UI庫,只要小夥伴們掌握了封裝組件的原理,其餘的都問題不大。但願有須要的小夥伴手動敲一遍,加深對封裝組件的過程。💪
若是以爲本文還不錯,記得點個贊哦!
歡迎你們加入,一塊兒學習前端,共同進步!