历史回顾:javascript
你是如何界定要不要造轮子的?于我而言,将须要多处调用的重复代码封装成组件、插件,把繁琐的操做流程开发成提效工具,后续能简化工做量,提升工做效率,就值得造轮子。为业务封组件、封插件,为提效造工具,作有价值的事,才能实现自我价值。css
咱们先来看看,此次造的什么轮子,针对咱们请假审批的需求,请假的时候选择日期选择器是带上下午的,这在移动端并很少见,一般是日历的形式,咱们的产品要求picker滚动器的形式。找了半天都没找到合适的。html
喏,就是这样效果,没得办法,只能本身上手造一个。如下就是我造轮子的过程。从先开发带半天的日期选择器组件,知足需求使用;业务里多处使用,封装成vue插件;封装完成发现包太大,进而对插件优化;一个精致的vue插件封装完成后,编写插件的使用文档,方便你们使用;而后上传到github,配置gh-pages,展示在线demo;最后发布到npm,一个三方插件就完成了。✌️✌️✌️前端
咱们先来看看封装好的带上、下的日期选择器,怎么用?👇vue
一个简单的基于vue的带上、下午的日期选择器java
在线地址:https://habc0807.github.io/vue-halfday-datepicker/index.htmlwebpack
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
没办法,我暂时放弃了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更新,从新计算数组里的数据值,及时更新选出的日期。组件就开发完成,里面其实还有不少细节地方须要注意,好比默认显示,更新后的显示等,我只是说了说主流程。
组件开发完成了,我萌生了封插件的想法。首先这个组件须要引用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是插件部分。
主要更改了 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"
}
复制代码
这里咱们预留了页面的入口,和插件的入口,先以组件的形式使用,没有问题后,再将组件打包成插件,再在页面中查看展示效果,或者修复插件中的小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-ui
的 mt-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'
},
复制代码
部署好的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官网注册,注册的时候,要记住本身的用户名、密码和邮箱,后面咱们还要用。
回到咱们vue插件的仓库根目录下,打开命令行,输入命令 npm login
,按照提示输入你的用户名和密码,再执行 npm publish
进行发布。发布成功,命令里会显示 npm的包名和版本号。
发包过程当中若是遇到包同名,或者版本号没更新的小问题,可自行搜索,很容易解决的。
但愿能帮助你们,了解编写插件的过程和思路,你会发如今业务中遨游,时而作些业务插件更能体现作业务的价值。快去试试吧,你也能够写出各式各样的小插件,欢迎在评论区跟我沟通交流。