從零制作自己的組件庫

前言

很多時候面對日常的工作業(yè)務需求,或者面對新項目時往往都是npm i element-ui -S安裝element或者Ant的組件庫,但如果自己想要面對特殊的需求需要定制組件往往需要不斷修改,改完又往往忘記了整理,最后就是不斷的重復。

你所寫的每一個 vue 文件都可以視為一個組件,隨著業(yè)務的不斷深入,頁面寫多了想將組件集合起來封裝成一個組件庫的想法也不斷加劇。僅在此寫下組件庫的構建思路和歷程,供自己記憶學習,也希望能幫助到你。

目錄構建

  • 推薦使用@vue/cli 進行項目的構建npm install -g @vue/cli

  • 命令行中輸入vue reate orange_collect快速初始化一個項目。

    image

  • 將src的目錄文件改為examples,用來寫組件相關文檔和事例。

  • 再新建一個src目錄,里面只放一個main.js用來作為打包入口

  • 在根目錄下新建一個 packages 文件夾,用來進行組件的編寫。

  • 在根目錄下新建一個vue.config.js文件,配置如下

    const NODE_ENV = 'development' // 開發(fā)環(huán)境 打包doc
    // const NODE_ENV = 'lib' // 組件庫 上傳npm
    const components = require('./build/compontents.json');
    const path = require('path')
    const baseConfig = {
        chainWebpack: config => {
            config.resolve.alias
            .set('@', path.resolve('examples'))
            .set('~', path.resolve('packages'))
            config.module
                .rule('js')
                .include
                .add('/packages')
                .end()
                .use('babel')
                .loader('babel-loader')
                .tap(options => {
                    // 修改它的選項...
                    return options
                })
        },
        //如有scss配置需求
        // css: {
        //   extract: false,
        //   loaderOptions: {
        //     // 給 sass-loader 傳遞選項
        //     sass: {
        //       data: `@import "public/css/ui.scss";`
        //     }
        //   },
        // }
    }
    const devConfig = {
        pages: {
            index: {
                entry: 'examples/main.js',
                template: 'public/index.html',
                filename: 'index.html',
            }
        },
        publicPath: './',
        outputDir: 'docs',
        ...baseConfig
    }
    const buildConfig = {
        configureWebpack: {
            entry: components,
            output: {
                filename: '[name].js',
                libraryTarget: 'commonjs2',
            },
        },
        outputDir: 'lib',
        productionSourceMap: false,
        ...baseConfig
    }
    
    module.exports = NODE_ENV === 'development' ? devConfig : buildConfig;
    

這里通過判斷NODE_ENV來判斷項目的打包方式,在development下把examples 加入編譯,將examples/main.js設置為文件入口。設置examplespackages的別名。

此時運行npm run serve已可以正常啟動項目。將HelloWorld頁面稍作修改,添加樣式和布局。

  • router中添加頁面路由
    import Vue from 'vue'
    import Router from 'vue-router'
    import Home from '../components/HelloWorld.vue'
    
    //組件
    import component from './component'
    
    Vue.use(Router)
    
    export default new Router({
      routes: [
        {
          path: '/',
          name: 'home',
          component: Home,
          redirect: '/component/installation',
          children: [
            //組件
            ...component,
          ]
        },
      ]
    })
    
    image

    相關界面如上,需要樣式和布局代碼可以去我的github上查看,再次不在贅述。

組件編寫

常規(guī)組件編寫

  • 我們組件的編寫都在packages文件夾中進行,舉個??(例子),現編寫一個測試的button組件。
    ├─packages                        
    │  └─orange_btn                      #組件模塊名稱文件夾
    │     ├─src 
    │     |  ├─orange_btn.vue                 
    │     └─index                        
    ├─index.js
    
  • 新建一個如上的目錄結構,接下來我們就需要在orange_btn.vue中編寫相關的業(yè)務代碼。通過props來定義組件的相關組件和狀態(tài)擴展。
    export default {
       props: {
       type: {
         type: String,
         default: "default"
       },
       size: String,
       icon: {
         type: String,
         default: ""
       }
     },
     name: "orange-button",
     data() {
       return {};
     },
    
  • 值得注意的是在orange_btn.vue中 name屬性尤為重要它是必須要寫的,是判斷是否唯一組件的標識,所以你寫的應該是不重名的。之后name將用來判定組件,如這里的nameorange-button在之后完
    成組件的注冊并且最終使用的時候則是<orange-button></orange-button>

組件圖標的引入和使用

  • 建議使用iconfont矢量圖庫將ui的圖標上傳,或在圖標庫中尋找合適的圖標后,下載至本地。
  • 將圖中的字體文件夾引入項目


    image
  • 在packages文件夾的index.js和examples的main.js中對字體文件進行引入import './assets/font/iconfont.css'
  • 使用iconfont+類名<i class="iconfont xxxx"/>

組件暴露

  • 每一個組件都需要如此步驟,先建立組件同名的文件夾,然后在orange_btn文件夾下的index·js下編寫暴露代碼,用于安裝單個組件

    import BlackBtn from './src/orange_btn.vue'
    
    // 為組件提供 install 安裝方法,供按需引入
    BlackBtn.install = function (Vue) {
      Vue.component(BlackBtn.name, BlackBtn)
    }
    
    // 默認導出組件
    export default BlackBtn
    
  • 在packages文件夾下新建一個index.js用來管理,可以避免我們的組件越來越多,需要重復引入,循環(huán)安裝所有組件。

     import orange_btn from './orange_btn'
     // 存儲組件列表
     const components = [
       orange_btn
     ]
     // 定義 install 方法,接收 Vue 作為參數。如果使用 use 注冊插件,則所有的組件都將被注冊
     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 default {
       // 導出的對象必須具有 install,才能被 Vue.use() 方法安裝
       install,
       // 以下是具體的組件列表
       orange_btn
     }
    

組件引入

  • 在examples用來寫組件相關文檔和事例。在examples的main.js中引入

    image

  • 使用<orange-button></orange-button>已可以在頁面中使用,由此可以編寫相關的文檔說明。

    image

打包配置

  • 在項目組件編寫過后,就可以將組件打包??上傳至npm使用
  • vue.config.js下的NODE_ENV改為lib模式
  • 新建build文件夾,寫一個方法
    const fs = require('fs-extra');
    const path = require('path');
    
    function isDir(dir) {
        return fs.lstatSync(dir).isDirectory();
    }
    
    function transformStr3(str) {
        var re = /-(\w)/g;
        return str.replace(re, function ($0, $1) {
            return $1.toUpperCase();
        });
    }
    
    // function firstUpperCase(str) {
    //     return str.toLowerCase().replace(/( |^)[a-z]/g, (L) => L.toUpperCase());
    // }
    
    const json = {};
    const dir = path.join(__dirname, '../packages');
    const files = fs.readdirSync(dir);
    files.forEach(file => {
        const absolutePath = path.join(dir, file);
        if (isDir(absolutePath)) {
            let fileKey = transformStr3(file.replace('orange_', ''))
            // console.log(fileKey)
            json[fileKey] = `/Users/chenzhikun/project/GitHub/orange_ui/packages/${file}/index.js`; //mac
            // json[fileKey] = `D:/projects/orange_ui/packages/${file}/index.js`;  //windows
        }
    });
    
  • 通過運行方法,獲得組件的路徑之后在vue.config.js中引入const components = require('./build/compontents.json')
  • 運行npm run build可以得到一個lib文件,這個文件就是我們最終要上傳到npm的文件。此時文件目錄如下。
image

npm發(fā)布

  • npm發(fā)布時,要將package.json中的private屬性值改為false并修改項目的版本號


    image
  • 我們沒有必要把所有的代碼都發(fā)布到npm上。在項目的根目錄創(chuàng)建一個.npmignore的文件,對多余的文件進行忽略.
    .DS_Store
    node_modules
    /dist
    
    # local env files
    .env.local
    .env.*.local
    
    # Log files
    npm-debug.log*
    yarn-debug.log*
    yarn-error.log*
    
    # Editor directories and files
    .idea
    .vscode
    *.suo
    *.ntvs*
    *.njsproj
    *.sln
    *.sw*
    
    # 以下是新增的
    # 要忽略目錄和指定文件
    build/
    examples/
    packages/
    public/
    src/
    util/
    vue.config.js
    babel.config.js
    *.map
    *.html
    
  • 執(zhí)行npm who am i命令, 如果沒有登陸則執(zhí)行npm login命令,系統會提示輸入賬戶和密碼。如果沒有則需要前往npm官網進行注冊。
  • 登陸之后執(zhí)行 npm publish 進行版本發(fā)布。
  • 在npm發(fā)布完成之后就可以在任意一項目中使用npm i orange_collect來安裝項目,之后在main.js中引入
    import orange from 'orange_collect'
    import 'orange_collect/lib/orange_collect.css'
    
    Vue.use(orange)
    

此時的組件均能通過標簽正常的使用。

image

小結

從零新建一個自己的組件庫至此就已經完成了,如果想我一樣團隊中有需要封裝自己的組件代碼庫,則可以試著像我一樣寫一個輪子一起用,我則是想收集各類有意思的按鈕進行自己的封裝。github地址

?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容