【vue 系列】開發組件、封裝成vue插件、編寫文檔、配置gh-pages分支demo、發佈npm包一波流

歷史回顧:javascript

你是如何界定要不要造輪子的?於我而言,將須要多處調用的重複代碼封裝成組件、插件,把繁瑣的操做流程開發成提效工具,後續能簡化工做量,提升工做效率,就值得造輪子。爲業務封組件、封插件,爲提效造工具,作有價值的事,才能實現自我價值。css

咱們先來看看,此次造的什麼輪子,針對咱們請假審批的需求,請假的時候選擇日期選擇器是帶上下午的,這在移動端並很少見,一般是日曆的形式,咱們的產品要求picker滾動器的形式。找了半天都沒找到合適的。html

就是這種日期選擇器👆。

喏,就是這樣效果,沒得辦法,只能本身上手造一個。如下就是我造輪子的過程。從先開發帶半天的日期選擇器組件,知足需求使用;業務裏多處使用,封裝成vue插件;封裝完成發現包太大,進而對插件優化;一個精緻的vue插件封裝完成後,編寫插件的使用文檔,方便你們使用;而後上傳到github,配置gh-pages,展示在線demo;最後發佈到npm,一個三方插件就完成了。✌️✌️✌️前端

咱們先來看看封裝好的帶上、下的日期選擇器,怎麼用?👇vue

vue-halfday-datepicker

一個簡單的基於vue的帶上、下午的日期選擇器java

Demo

在線地址:https://habc0807.github.io/vue-halfday-datepicker/index.htmlwebpack

特色

  • 移動端
  • 帶上、下午
  • 日期選擇器
  • vue插件

安裝

npm i vue-halfday-datepicker -D
cnpm i vue-halfday-datepicker -D
yarn add vue-halfday-datepicker -D
複製代碼

引入和註冊

在單頁面應用的入口文件裏引入和註冊git

import VueHalfdayDatepicker from 'vue-halfday-datepicker'
Vue.use(VueHalfdayDatepicker)
複製代碼

使用

<template>
  <div id="app">
    <h2>一個基於vue的日期選擇器Demo</h2>

    <div class="pickerSelect" @click="onOpenPicker">{{ pickerValue }}</div>
    <vue-halfday-datepicker :show="isShow" @onConfirm="onConfirmHandle" @onCancel="onCancelHandle"/>
  </div>
</template>

<script>
export default {
  name: 'app',
  data () {
    return {
      isShow: false,
      pickerValue: '測試一下:請選擇'
    }
  },
  methods: {
    onOpenPicker(e) {
        this.isShow = true
    },
    onConfirmHandle(v) {
        this.value = v
        this.pickerValue = v
        this.isShow = false
    },
    onCancelHandle(e) {
        this.isShow = false
    }
  },
}
</script>
<style>
</style>
複製代碼

若是以爲插件還不錯,就給個Star,助力下,你的支持,是我輸出的動力~~~ github: vue-halfday-datepickergithub

如何開發一個帶上、下午的日期選擇器組件

尋找解決方案

最初的時候,我想省事,找個三方直接用,在github上扒拉了半天,又扒了vue的UI組件庫們,看了一圈,發現VUX的datetime 竟然有這個組件。開森,趕忙試試,開始按需引入這個組件,經過VUX官網的手動配置使用,配置真繁瑣,重點配完還不能用。固然我不會輕易放棄的,從頭至尾按照配置再來一遍,依舊很差使。web

二次封裝picker

沒辦法,我暫時放棄了VUX。另闢捷徑,日期選擇器picker,不也是picker嗎,爲何不基於picker的基礎上作二次封裝呢?

因而我找到了 Mint UI,使用它的 picker 作二次封裝。不得不認可 Mint UI 的快速上手文檔寫的很贊,配置起來很順手。由於只須要使用一個組件,按需引入須要藉助 babel-plugin-component ,以達到減少項目體積的目的。首先,安裝 npm install babel-plugin-component -D,而後將 .babelrc 修改成:

{
  "presets": [
    ["es2015", { "modules": false }]
  ],
  "plugins": [["component", [
    {
      "libraryName": "mint-ui",
      "style": true
    }
  ]]]
}
複製代碼

日期選擇器如何開發

固然最重要的是 picker 的 slots 四列數組的數據處理,以及 picker 改變的數據更新。先來看看 slots :

slots: [
    {
        flex: 1,
        values: yearsArr,
        className: 'slot1',
        textAlign: 'center',
        defaultIndex: defalutYear,
    }, 
    {
        flex: 1,
        values: monthsArr,
        className: 'slot2',
        textAlign: 'center',
        defaultIndex: defalutMonth
    },
    {
        flex: 1,
        values: daysArr,
        className: 'slot3',
        textAlign: 'center',
        defaultIndex: defalutDay
    },
    {
        flex: 1,
        values: noonArr,
        className: 'slot4',
        textAlign: 'center',
        defaultIndex: 0,
    }
]
複製代碼

咱們須要四列數組,分別是年份數組,當前年份對應的月份數組,當前月份對應的天數數組,以及一個上、下午數組。其中月份數組一般都是 1 ~ 12月,上、下午數組也很簡單,年份數組咱們默認指定先後10年就夠用了,須要特殊計算的是天數數組。其實計算規則大體是是不是2月,如果經過是不是閏年計算出天數,若不是 4, 6, 9, 11月份爲30天,其它月份爲31天。嗯,就醬,來看代碼👇。

/** * 是不是閏年 * @param {*} year */
function isLeapYear (year) {
  return year % 100 !== 0 && year % 4 === 0 || year % 400 === 0
}

/** * 計算每一年的每月的天數 * @param {*} year * @param {*} month */
function getMaxDay (year, month) {
  year = parseFloat(year)
  month = parseFloat(month)
  if (month === 2) {
    return isLeapYear(year) ? 29 : 28
  }

  return [4, 6, 9, 11].indexOf(month) >= 0 ? 30 : 31
}
複製代碼

每次picker更新,從新計算數組裏的數據值,及時更新選出的日期。組件就開發完成,裏面其實還有不少細節地方須要注意,好比默認顯示,更新後的顯示等,我只是說了說主流程。

如何封裝一個vue插件

組件開發完成了,我萌生了封插件的想法。首先這個組件須要引用mint-ui三方,按需引入 picker,其次,在項目根目錄下添加 .babelrc 文件來配置按需加載。這一些列的操做,若是後續有需求或者其餘小夥伴也要用它的話,就會以爲比較麻煩。咱們這個多頁面應用,就要把上述的流程再操做一遍。還不如封裝一個 vue 插件,用着多方便。

從業務的價值出發,值得造火箭,若是能將以上流程封裝成 vue 插件,後續只要引入使用就好了。配置流程,按需加載什麼的都放到 vue 插件裏,爲業務造輪子,這就是我要作的事情。

項目初始化

查封裝vue插件的資料的時候,看到有人推薦 webpack-simple,我就試試了試,還蠻好用。經過 vue init webpack-simple vue-插件名,建立出已 vue-插件名命名的文件夾,項目的目錄樹以下。

.
├── README.md
├── dist
├── index.html
├── package.json
├── src
│   ├── App.vue
│   ├── assets
│   │   └── logo.png
│   ├── lib            
│   │   ├── VueHalfdayDatepicker.vue
│   │   └── index.js
│   ├── main.js
└── webpack.config.js
複製代碼

很簡單,前端的猿猿們一眼就能看的懂吧,其中src爲源碼部分,lib是插件部分。

修改配置項

修改package.json

主要更改了 name、main、author、repository,具體以下:

  • name 指定插件名稱
  • main 插件最後的構建文件路徑
  • author 做者的基本信息
  • repository 倉庫的基本信息
{
  "name": "vue-halfday-datepicker",
  "description": "A date picker",
  "main": "dist/vue-halfday-datepicker.js",
  "version": "1.0.1",
  "author": "habc0807 <gao0807@foxmail.com>",
  "license": "MIT",
  "private": false,
  "scripts": {
    "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot",
    "build": "cross-env NODE_ENV=production webpack --progress --hide-modules"
  },
  "repository": {
    "type": "git",
    "url": "git+https://github.com/habc0807/vue-halfday-datepicker.git"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ],
  "devDependencies": {
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-plugin-component": "^1.1.1",
    "babel-preset-env": "^1.6.0",
    "babel-preset-stage-3": "^6.24.1",
    "cross-env": "^5.0.5",
    "css-loader": "^0.28.7",
    "file-loader": "^1.1.4",
    "mint-ui": "^2.2.13",
    "vue": "^2.5.11",
    "vue-loader": "^13.0.5",
    "vue-template-compiler": "^2.4.4",
    "webpack": "^3.6.0",
    "webpack-bundle-analyzer": "^3.8.0",
    "webpack-bundle-tracker": "^1.0.0-alpha.1",
    "webpack-dev-server": "^2.9.1"
  },
  "bugs": {
    "url": "https://github.com/habc0807/vue-halfday-datepicker/issues"
  },
  "homepage": "https://github.com/habc0807/vvue-halfday-datepicker#readme"
}
複製代碼

修改 webpack.config.js

這裏咱們預留了頁面的入口,和插件的入口,先以組件的形式使用,沒有問題後,再將組件打包成插件,再在頁面中查看展示效果,或者修復插件中的小bug。

entry: './src/main.js', // 頁面的入口
  // entry: './src/lib/index.js', // 插件的入口
output: {
    path: path.resolve(__dirname, './dist'),
    publicPath: '/dist/',
    filename: 'build.js', // 頁面的生成文件
    // filename: 'vue-halfday-datepicker.js', // 插件的生成文件
    libraryTarget: 'umd',
    umdNamedDefine: true
},
複製代碼

後續在優化插件的過程當中,添加一些其它配置,最終的 webpack.config.js 在插件優化部分中展現。

封裝插件

VueHalfdayDatepicker.vue 插件的具體內容以下,其中須要注意的地方,這個插件的封裝使用了 mint-uimt-picker。我主要要作的事情就是 picker 的四列數組 slots,第一個模塊介紹過,這裏就不贅述了。

<template>
    <div v-show="show" class="half-day-date-picker">
        <div class="bg"></div>
        <div class="select-date-container">
            <section class="picker-wrap">
                <div class="picker-toolbar">
                    <div class="btn cancel" @click="onCancel">取消</div>
                    <div class="btn confirm" @click="onConfirm">肯定</div>
                </div>

                <mt-picker 
                    :valueKey="''"
                    :defaultIndex=10
                    :visibleItemCount=9
                    :slots="slots" 
                    @change="onValuesChange"
                ></mt-picker>
            </section>
        </div>
    </div>
</template>

<script>
import { Picker } from 'mint-ui'
import 'mint-ui/lib/style.css'

import {
    yearsArr,
    monthsArr,
    daysArr,
    noonArr,
    defalutYear,
    defalutMonth,
    defalutDay
} from '../tools/makeData.js'

export default {
    name: 'vue-halfday-datepicker',
    props: {
        show: {
            type: Boolean,
            required: true,
            default: () => null,
        }
    },
    components: {
        [Picker.name]: Picker,
    },
    data: function() {
        return {
            pickerValue: '',
            slots: [
                {
                    flex: 1,
                    values: yearsArr,
                    className: 'slot1',
                    textAlign: 'center',
                    defaultIndex: defalutYear,
                }, 
                {
                    flex: 1,
                    values: monthsArr,
                    className: 'slot2',
                    textAlign: 'center',
                    defaultIndex: defalutMonth
                },
                {
                    flex: 1,
                    values: daysArr,
                    className: 'slot3',
                    textAlign: 'center',
                    defaultIndex: defalutDay
                },
                {
                    flex: 1,
                    values: noonArr,
                    className: 'slot4',
                    textAlign: 'center',
                    defaultIndex: 0,
                }
            ],
        }
    },
    methods: {
        onOpenPicker(e) {
            this.$emit('onOpenPicker')
        },
        onConfirm(e) {
            this.$emit('onConfirm', this.pickerValue)
        },
        onCancel(e) {
            this.$emit('onCancel')
        },
        /** picker改變的處理 */
        onValuesChange(picker, values) {
            // 按照時間組合字符串
            const pickerValue = values[0] + '-' + values[1] + '-' + values[2] + ' ' + values[3]
            this.pickerValue = pickerValue
            this.$emit('onValuesChange', pickerValue)
        },
    },
}
</script>
<style scoped>
	// …
</style>
複製代碼

將此組件封裝成插件,vue插件的格式要經過 install 來掛載組件,使用 Vue.component 來註冊一個插件,在外部 use 一個插件, index.js 的完整內容以下。

import VueHalfdayDatepicker from './VueHalfdayDatepicker.vue'

const datePicker = {
  install: function(Vue) {
    Vue.component(VueHalfdayDatepicker.name, VueHalfdayDatepicker)
  }
}

// 這裏的判斷很重要
if (typeof window !== 'undefined' && window.Vue) { 
  window.Vue.use(datePicker) 
}
export default datePicker
複製代碼

測試插件

如何測試一個插件開發是否成功呢,我沒有直接去構建插件,而是以直接引用本地插件的方式,在 main.js 中引入插件

import VueHalfdayDatepicker from '../dist/vue-halfday-datepicker.js'
Vue.use(VueHalfdayDatepicker)
複製代碼

App.vue 中使用組件

<template>
  <div id="app">
    <h2>一個基於vue的日期選擇器Demo</h2>

    <div class="pickerSelect" @click="onOpenPicker">{{ pickerValue }}</div>
    <vue-halfday-datepicker :show="isShow" @onConfirm="onConfirmHandle" @onCancel="onCancelHandle"/>
  </div>
</template>

<script>
export default {
  name: 'app',
  data () {
    return {
      isShow: false,
      pickerValue: '測試一下:請選擇'
    }
  },
  methods: {
    onOpenPicker(e) {
        this.isShow = true
    },
    onConfirmHandle(v) {
        this.value = v
        this.pickerValue = v
        this.isShow = false
    },
    onCancelHandle(e) {
        this.isShow = false
    }
  },
}
</script>

<style>
	// …
</style>
複製代碼

執行 npm run dev,緊接着在頁面中查看插件,修復插件bug等,在頁面中查看沒有問題了。接着修改 webpack.config.js 的入口文件,和生成文件名稱。

// entry: './src/main.js', // 頁面的入口
  entry: './src/lib/index.js', // 插件的入口
  output: {
    path: path.resolve(__dirname, './dist'),
    publicPath: '/dist/',
    // filename: 'build.js', // 頁面的生成文件
    filename: 'vue-halfday-datepicker.js', // 插件的生成文件
    libraryTarget: 'umd',
    umdNamedDefine: true
},
複製代碼

執行 npm run build,在目錄 dist文件夾下 構建生成插件 vue-halfday-datepicker.js。而後再配置回頁面的構建,查看插件效果。

插件優化

一個vue插件基本上就開發好了,咱們想看看構建生成的插件各個模塊的大小,有哪些可優化的空間,能夠借用 webpack-bundle-analyzer 可視化工具查看。 在項目根目錄下使用命令行 cnpm i webpack-bundle-analyzer,去 webpack.config.js 中配置

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

plugins: [
    new BundleAnalyzerPlugin()
]
複製代碼

執行 npm run dev,看到打包後的插件的各個模塊的大小。咱們發現插件把 vue 打包進去了,是由於 mint-ui 引入了 vue。插件大小,Parsed size: 161.33kb。

咱們經過配置 externals來防止將某些 import 的包(package)打包到 bundle 中,而是在運行時(runtime)再去從外部獲取這些擴展依賴。經過設置 externals 防止把 vue 打包進去,打包後插件包小了許多,Parsed size: 64.46kb。

externals: {
    vue: 'Vue'
},
複製代碼

推到github上,在gh-pages上配置demo

部署好的DEMO地址,快來看看效果。

猿猿們git操做都很溜,我就不贅述github的基本操做了,當咱們把插件庫推到github以後,默認是推到master分支上,而後新建分支 gh-pages,將master 分支上的內容merge 到gh-pages分支上,並提交到遠程。須要注意的點是 gh-pages 分支是github提供的靜態網站部署器,默認會讀取項目根目錄下的 index.html,個人index.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no,viewport-fit=cover">
    <title>vue-halfday-datepicker</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  </head>
  <body>
    <div id="app"></div>
    <script src="./dist/build.js"></script>
  </body>
</html>
複製代碼

其中 <script src="./dist/build.js"></script> 裏的 dist/build.js 是頁面的構建文件,注意 .gitignore 中不要配置 dist 文件,否則 builds.js 文件就讀取不到了。部署好的DEMO地址,快來看看效果。

發佈插件,發佈一個npm包

娃哈哈,到最後一步了,咱們來看看怎麼發佈。熟悉該流程的猿猿們,就能夠忽悠該模塊了,若是本文,能幫助到你,能夠爲我助力點贊。【不害臊的要關注,要贊,嘻嘻~】

npm官網註冊

npm官網註冊,註冊的時候,要記住本身的用戶名、密碼和郵箱,後面咱們還要用。

npm包發佈

回到咱們vue插件的倉庫根目錄下,打開命令行,輸入命令 npm login ,按照提示輸入你的用戶名和密碼,再執行 npm publish 進行發佈。發佈成功,命令裏會顯示 npm的包名和版本號。

發包過程當中若是遇到包同名,或者版本號沒更新的小問題,可自行搜索,很容易解決的。

總結

但願能幫助你們,瞭解編寫插件的過程和思路,你會發如今業務中遨遊,時而作些業務插件更能體現作業務的價值。快去試試吧,你也能夠寫出各式各樣的小插件,歡迎在評論區跟我溝通交流。

相關文章
相關標籤/搜索