從零實現一套屬於本身的UI框架-發佈到npm

現在前端工程師的要求愈來愈高了,須要掌握的技術點愈來愈多了,會一些基本的前端技能徹底適應不了快速變化的前端領域了。接下來我將從零實現一個本身的UI組件庫併發布到npm上,提供給須要的朋友參考也總結下本身對封裝組件的理解方便之後複習。html

fly
本項目以button按鈕爲例,詳細的記錄一下封裝一個Button UI組件每個步驟以及須要注意的地方:前端

效果

Element UI

Mc UI

須要技能

  1. 須要掌握 Vue 的基本語法
  2. 組件之間的通訊
  3. 插槽的用法
  4. vue-cli3 建立項目、打包
  5. npm & git 的用法

建立項目

檢查 node 環境配置

先本地全局安裝node環境,vue的運行是依賴於nodenpm的管理工具來實現的,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

  1. 選擇那些特性須要安裝在項目中
(*) Babel
 ( ) TypeScript
 ( ) Progressive Web App (PWA) Support
 ( ) Router
 ( ) Vuex
 (*) CSS Pre-processors
 (*) Linter / Formatter
 ( ) Unit Testing
 ( ) E2E Testing

系統默認的包含了基本的 Babel + ESLint 設置的 preset,咱們只須要選擇CSS配置。移動鍵盤上下鍵選擇須要的特性,按下鍵盤空格鍵便可選中git

  1. 安裝哪種 CSS 預處理語言
Sass/SCSS (with dart-sass)
  Sass/SCSS (with node-sass)
  Less
  Stylus

因爲Element UI中的樣式採用Sass,因此咱們選擇第一項便可
爲何不選擇第二項呢?
由於dart-sass比node-sass更好下載github

  1. 選擇代碼風格
ESLint with error prevention only
  ESLint + Airbnb config
  ESLint + Standard config
  ESLint + Prettier

因我的喜愛選擇便可,我比較喜歡第三種web

  1. 那種方式進行代碼格式檢測
(*) Lint on save
 ( ) Lint and fix on commit

選擇Ctrl+S保存時檢測代碼格式便可面試

  1. 配置文件生成方式
In dedicated config files
  In package.json

因我的喜愛,我比較喜歡選擇第二種vue-cli

  1. 是否保存預配置
Save this as a preset for future projects? (y/N)

看項目須要,我這裏選擇 N。回車後,系統會自動幫咱們把選擇的配置集成到模板中,而後生成一個完整的項目。

blockchain

核心邏輯

咱們大體按照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>的實現
  1. <template>
<template>
  <button class="mc-button">
    <span>
      <slot></slot> // slot表示插槽
    </span>
  </button>
</template>

注意:爲何要在slot插槽外面加個span標籤呢?爲了美觀,每一個自定義button組件間相互有點間距🤭

  1. <script>
export default {
  name: 'McButton'
}

注意:組件中填寫name屬性,是爲了封裝組件提供install方法時,動態獲取每一個組件名進行組件註冊

  1. <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表示禁止用戶選中文字

  1. 效果

basic_button

常見類型

  • 基礎<mc-botton type="xxx" class="mc-bottom"></mc-botton>的實現

常見的類型有:primary / success / warning / danger / info / text

  1. <template>
<button 
    class="mc-button" 
    :class="[
      `mc-button--${type}`
    ]">
    ...
</button>

注意:爲何綁定class時採用數組形式,而不用對象形式,由於會有多個動態綁定的屬性,且使用對象的形式,這樣就只有數組裏能夠放多個動態屬性,且屬性能夠爲對象

  1. <script>
props: {
    type: {
      type: String,
      default: 'default'
    }
}

注意:這裏接收屬性爲何不用數組的形式?由於咱們是封裝組件給別人用的,因此要限制一些條件,不能讓用戶隨意的輸入

  1. <style>

該功能時,樣式沒有改動

  1. 效果

type_button

樸素按鈕

  • 基礎<mc-botton plain class="mc-bottom"></mc-botton>的實現
  1. <template>
<button 
    class="mc-button" 
    :class="[
      `mc-button--${type}`,
      {
            'is-plain': plain
       }
    ]">
    ...
</button>

注意:爲何綁定class時採用數組形式,而不用對象形式,由於會有多個動態綁定的屬性,且使用對象的形式,這樣就只有數組裏能夠放多個動態屬性,且屬性能夠爲對象

  1. <script>
plain: {
  type: Boolean,
  default: false
}
  1. <style>
&.is-plain:hover,
  &.is-plain:focus {
    background: #fff;
    border-color: #409eff;
    color: #409eff;
}
  1. 效果

plain_button

添加圓角

  • 基礎<mc-botton round class="mc-bottom"></mc-botton>的實現
  1. <template>
<button 
    class="mc-button" 
    :class="[
      `mc-button--${type}`,
      {
            ...
            'is-round': round
       }
    ]">
    ...
</button>
  1. <script>
round: {
      type: Boolean,
      default: false
}
  1. <style>
&.is-round {
    border-radius: 20px;
    padding: 12px 23px;
 }
  1. 效果

round_button

添加圓形

  • 基礎<mc-botton class="mc-bottom is-circle"></mc-botton>的實現
  1. <template>
<button 
    class="mc-button" 
    :class="[
      `mc-button--${type}`,
      {
            ...
            'is-circle': circle
       }
    ]">
    ...
</button>
  1. <script>
circle: {
      type: Boolean,
      default: false
}
  1. <style>
&.is-circle {
    border-radius: 50%;
    padding: 12px;
}
  1. 效果

circle_button

是否禁用

  • 基礎<mc-botton class="mc-bottom" disabled></mc-botton>的實現
  1. <template>
<button 
    ...
    :disabled="disabled"
    :class="[
      `mc-button--${type}`,
      {
            ...
            'is-disabled': disabled
       }
    ]">
    ...
</button>
  1. <script>
disabled: {
      type: Boolean,
      default: false
}

注意:添加是否被禁用時有兩個做用:第1、讓用戶不能點擊;第2、改變按鈕樣式

  1. 效果

circle_button

添加圖標

  • 基礎<mc-botton icon="el-icon-check" class="mc-bottom"></mc-botton>的實現
  1. <template>
<button
    ...
    >
    <i :class="icon" v-if="icon"></i>
    <!-- 若是沒有傳入插槽的時候才顯示 -->
    <span v-if="$slots.default"><slot></slot></span>
</button>
  1. <script>
icon: {
    type: String,
    default: ''
}
  1. <style>
.mc-button [class*=mc-icon-]+span {
  margin-left: 5px;
}

i標籤上加v-if的目的:讓用戶便可以上傳圖標也能夠上傳文字或者上傳文字和圖標

注意:既傳圖標也傳文字的話,圖標和文字隔的很近,咱們須要特殊處理下; 可是若是特性處理的話,單獨的圖標會不居中顯示;因此咱們要使用$slots獲取包含有插槽的才讓其顯示處理

  1. 效果

icon_button

點擊事件

  • 基礎<mc-botton class="mc-bottom" @click="handleClick"></mc-botton>的實現
  1. <template>
<button
    ...
    @click="handleClick"
    >
    ...
</button>
  1. <script>
methods: {
    handleClick (e) {
        this.$emit('click', e) // 向父組件派發一個click事件,e表示攜帶的參數
    }
}
  1. 效果

click_button

打包

在Vue-cli3的 官方文檔 中有個構建目標有明確的說明怎麼打包成一個應用或者一個庫!此時,咱們須要在package.json中添加一條打包命令

vue-cli-service build --target lib 指定打包的文件

而後控制檯執行yarn lib便可將咱們的組件庫包括字體圖標一塊兒打包生成一個dist文件夾

上傳github & 發佈 npm

將代碼上傳到github

首先登陸github 官網 建立一個新的倉庫,而後複製新倉庫的git地址。 而後在咱們本地建立的項目根目錄執行git init,初始化git,而後再終端執行如下命令:

git remote add origin 
git add .
git commit -am ":rocket: project init"
git push -u origin master

click_button

你們有沒有發現我提交的commit不同,其實就是用到了gitmoji這個依賴而已,簡單說下他的用法:

  1. 全局安裝這個依賴 npm install -g gitmoji-cli
  2. commit 提交代碼時,加上表情符號就好。例如: " xxxx", 這樣你提交的代碼註釋前面就會加一個emoji圖標,很炫酷的哦,小夥伴們能夠試一下🤭
  3. 常見的emoji有:等等
將代碼發佈到npm

因爲咱們開發的組件庫是給別人用的,咱們沒有必要把全部的代碼都發布到npm上。因此咱們須要在項目的根目錄建立一個.npmignore的文件,忽略那些文件上傳

// .npmignore
# 忽略目錄
test/
packages/
public/
 
# 忽略指定文件
vue.config.js
babel.config.js
*.map
.editorconfig.js

注意:因爲咱們要上傳到npm上,因此咱們本地npm的源要使用npm的源,不能使用淘寶源或其餘的。
查看一下本地電腦全部的源:
nrm_list
一切準備工做作好後,打開終端,執行npm login進行登陸

  • 登陸

執行npm login命令,系統會提示輸入帳戶和密碼。若是沒有npm帳戶,請註冊 → npm官網

  • 發佈

若帳戶登陸成功後,就能夠再次執行 npm publish 進行發佈

  • 注意
  1. 必定要在package.json的scripts中添加main方便其餘人下載時找到對應打包的文件
  2. 上傳到npm上時,要將package.json中的private屬性值改成false
  3. 修改源碼後發佈到npm時必定要更改項目的版本號

代碼倉庫

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庫,只要小夥伴們掌握了封裝組件的原理,其餘的都問題不大。但願有須要的小夥伴手動敲一遍,加深對封裝組件的過程。💪

最後

若是以爲本文還不錯,記得點個贊哦!

歡迎你們加入,一塊兒學習前端,共同進步!
cmd-markdown-logo
cmd-markdown-logo

相關文章
相關標籤/搜索