Open lostvita opened 5 years ago
即便是一个青铜,也要用王者的心去编码!
Github上关于Vue的UI库,大大小小不计其数,即便是已经被推广使用的成熟库,也有很多。很多时候,我们自研一套UI库,不是想要做得多牛逼,竞争过别人(事实咱也干不过人家,除非你不是一个人在战斗。毕竟这不仅是个技术活,还是个体力活),我们仅仅是源自一个青铜对王者的仰望或者是为满足内心的需求。这里跟大家讲一个一步一步自研UI库的故事。
开发一套UI库,做成不难(这里指的是半半半成品,全品也好难。。。),做好很难。但不慌,咱有秘籍:
Vue.js
CSS3
一套成熟的开源UI库一般都具备以下几个特点:
因此,它们的目录架构也出现了主要的两种形式: & 有点大同小异,这里我们按照第一种架构去开发。
观察社区几大UI库发现,它们都是基于webpack搭建了自己的构建配置,包括本地开发、生产环境构建、UI库的打包等,建立一套自己的构建生态。我们就不同了,业余一点(其实是善于应用开源工具),我们的docs文档是基于vuepress的,vuepress有自己一套的构建体系,所以我们只需要针对UI组件源码写一份打包配置就好了。
webpack
下面开始搭建打包配置(其实就是很久以前我们做的基于webpack的构建,现在cli用得多了,配置也不会写了,码耶): 首先在根目录建立config和build文件夹,然后往两个目录分别新建文件,如下:
config
build
不是说只有一份打包的配置文件么?咋还多了那么多文件呢?是这样,虽然我们是业余的,但咱也想做得专业一点对吧(有利于对配置进行扩展管理)!
我们看config/index.js有什么? 好像注释也很清楚?这些定义最终都被应用在_webpack.lib.conf.js_中。
再看看build/webpack.base.conf.js里面的关键配置: 基础配置里面的entry和output会被_webpack.lib.conf_覆写;rules定义一系列loader的转换规则,其中eslint的校验就是在这里定义了一个eslint-loader。
build/webpack.base.conf.js
entry
output
rules
最后看一眼build/webpack.lib.js配置: lib里面重写entry的规则是,根据传参值(components)分别走不同的入口文件,一种只有一个./src/index.js,这个是UI对外注册的入口文件(这使得我们可以引入整个UI);另一种是各个UI组件的注册入口文件(这使得我们可以按需引入组件);
build/webpack.lib.js
先给大家贴图直观感受下源码的目录结构:
那实际打包的时候走的是哪一种呢?真相是都走!在_build-lib.js_中,执行了三次打包,打包输出效果如下: 第一次的打包的输出是经过压缩的(压缩css样式表文件,可以看到输出文件带了min后缀),第二次是未压缩的,最后一次是对各组件分别打包。(PS:我很想给大家用红圈圈在图上标记下,奈何设备不允许。。。数度哽咽......Ubuntu系统下大家有好用的截图标记工具可以推荐下吗?)
前面扎好了马步,终于到修炼招式的阶段了! 我们都知道,在应用某个插件的时候需要经过下面代码的调用:
import Ange from 'ange-ui' Vue.use(Ange)
好奇下Vue.use在做什么处理呢?它其实就是注册/安装这个插件,根据use内部的定义,它通过调用install方法去注册插件,那么,Ange就必须是一个Function(会被use当做是install方法调用)或者是一个包含了install方法的Object。
Vue.use
Function
install
Object
道理我都懂,可是install方法里面到底写些什么?
试想一下,我们希望在项目的任意位置都能引用这个插件,那我们的每一个组件是不是要在全局注册?比如通过下面这种方式全局注册组件:
Vue.component('pagination', pagination)
没错,install方法内部就是批量地全局注册组件。
首先我们按照下图的方式新建目录和文件: 在_src目录的index.js_文件中定义install方法:
import './scss/ange.scss' // 引入组件样式表,也可以让用户在使用的时候自行引入 import components from './components' function install(Vue, opts = {}) { Object.values(components).forEach((each) => { Vue.component(each.name, each) }) } if (typeof window !== 'undefined' && window.Vue) { install(window.Vue) } export default { version: '1.0.0', install, ...components }
核心逻辑install就是对所有的组件循环注册在全局。components目录的_index.js_则是逐个对外暴露组件对象,其次每一个组件也有一个index.js,它的作用是为当前组件注入install方法。理所当然地,install里面是将该组件注册在全局,于是我们可以按需引用组件。
组件开发的通用模板
<template> <component :is="'button'"></component> </template> <script> export default { name: 'ag-button', props: {} } </script>
component是vue的内置组件,is参数设置成button,表明最终渲染的html是button标签,我们也可以直接使用button标签,但我们的按钮组件不一定是button,还可能是a标签,为了更好的拓展,这里使用component。
is
button
声明组件参数
export default { name: 'ag-button', props: { // 按钮类别 primary: Boolean, secondary: Boolean, dashed: Boolean, link: Boolean, // 按钮状态 color: { type: String, validator (val) { return new Set(['success', 'warn', 'danger']).has(val) } }, // 按钮尺寸 size: { type: String, validator (val) { return new Set(['large', 'normal', 'small']).has(val) } }, // 图标按钮 icon: String, // 原型按钮(一般结合图标按钮使用) circle: Boolean, // 外链按钮 external: Boolean, // 异步按钮 loading: Boolean } }
完善组件模板
<template> <component :is="tag" class="ange-btn" :class="[ btnSize, color, { 'default': isDefault, 'primary': primary, 'secondary': secondary, 'dashed': dashed, 'link': link, 'icon': icon, 'circle': circle }]" @click="$emit('click', $event)" :disabled="loading">ku <span class="ange-btn-content"> <!-- 图标按钮依赖 ag-icon 组件 --> <ag-icon v-if="icon" :icon="icon" /> <slot /> <!-- 插槽接收按钮文本 --> </span> </component> </template> <script> import Icon from '../icon/Icon' export default { // ... computed: { tag () { return this.external ? 'a' : 'button' }, isDefault() { const type = [this.primary, this.secondary, this.dashed, this.link] return type.every((each) => !each) }, btnSize() { return this.size || 'normal' } } } </script>
剩下的工作就是写好样式表了,你可以选择直接写在vue文件里面,也可以新建_scss/scss_样式表。
组件应用及效果(在线查看)
以上,便开发好一个button组件了,执行一下node build-lib.js或者npm run build:lib(现在package.json声明script)就可以打包这个UI框架,然后再将其发布到npm平台(如果你想...)
node build-lib.js
npm run build:lib
在线查看 Ange UI Docs 写好文档是一个库不可或缺的部分,写的过程通过实际应用各组件,还可以对其进行测试校验。前面说到,我们的文档要基于vuepress开发,简洁的Markdown写法,很是方便。这里一篇 指南 可以很好地帮助你,它告诉了你如何搭建架构,写好配置以及部署上线,或者参考我这个 仓库 的配置。
假设 docs/views/button.md 是你的button组件的文档页面,要如何引用你的组件? Ange UI内置引入了样式表,这里可以不用再引入,也可以按需只引入button组件:
import '@scss/ange.scss' import Button from '@component/button' Vue.use(Button)
至此,文档也就写好了!
最后的最后,按照 vuepress doc 部署到你的github仓库上就可以了!
本文通过button组件从0到1的开发,深入浅出阐述了Vue UI框架的开发流程,你对Vue.js的理解越深,组件的功能越复杂,你就会用到更多的高级用法。通过自研UI框架,我们也有很大的收获:
PS:CSS其实是UI开发中占比很重的部分,大家按照自己的风格组件化开发就好。给推荐几个很棒的配色网站: ColorDrop Color Hunt NIPPON COLORS
最后,希望大家也能多多去尝试,这个青铜自研UI库的故事到这里就结束了。
The end.
前言
即便是一个青铜,也要用王者的心去编码!
Github上关于Vue的UI库,大大小小不计其数,即便是已经被推广使用的成熟库,也有很多。很多时候,我们自研一套UI库,不是想要做得多牛逼,竞争过别人(事实咱也干不过人家,除非你不是一个人在战斗。毕竟这不仅是个技术活,还是个体力活),我们仅仅是源自一个青铜对王者的仰望或者是为满足内心的需求。这里跟大家讲一个一步一步自研UI库的故事。
开发一套UI库,做成不难(这里指的是半半半成品,全品也好难。。。),做好很难。但不慌,咱有秘籍:
Vue.js
和CSS3
还是有一定的技术要求。那我要多牛逼才能写好这个UI库啊?这取决于你这套UI库的实现高度。UI库的必要架构
一套成熟的开源UI库一般都具备以下几个特点:
因此,它们的目录架构也出现了主要的两种形式:
&
有点大同小异,这里我们按照第一种架构去开发。
搭建UI开发环境
观察社区几大UI库发现,它们都是基于
webpack
搭建了自己的构建配置,包括本地开发、生产环境构建、UI库的打包等,建立一套自己的构建生态。我们就不同了,业余一点(其实是善于应用开源工具),我们的docs文档是基于vuepress的,vuepress有自己一套的构建体系,所以我们只需要针对UI组件源码写一份打包配置就好了。下面开始搭建打包配置(其实就是很久以前我们做的基于webpack的构建,现在cli用得多了,配置也不会写了,码耶): 首先在根目录建立![image](https://user-images.githubusercontent.com/26505680/59190930-a0376280-8bb0-11e9-9811-b8f7b594e24d.png)
config
和build
文件夹,然后往两个目录分别新建文件,如下:不是说只有一份打包的配置文件么?咋还多了那么多文件呢?是这样,虽然我们是业余的,但咱也想做得专业一点对吧(有利于对配置进行扩展管理)!
我们看config/index.js有什么?
好像注释也很清楚?这些定义最终都被应用在_webpack.lib.conf.js_中。
再看看
基础配置里面的
build/webpack.base.conf.js
里面的关键配置:entry
和output
会被_webpack.lib.conf_覆写;rules
定义一系列loader的转换规则,其中eslint的校验就是在这里定义了一个eslint-loader。最后看一眼
lib里面重写
build/webpack.lib.js
配置:entry
的规则是,根据传参值(components)分别走不同的入口文件,一种只有一个./src/index.js,这个是UI对外注册的入口文件(这使得我们可以引入整个UI);另一种是各个UI组件的注册入口文件(这使得我们可以按需引入组件);先给大家贴图直观感受下源码的目录结构:![image](https://user-images.githubusercontent.com/26505680/59191067-0623ea00-8bb1-11e9-90ef-f3a1cc699e02.png)
那实际打包的时候走的是哪一种呢?真相是都走!在_build-lib.js_中,执行了三次打包,打包输出效果如下:
第一次的打包的输出是经过压缩的(压缩css样式表文件,可以看到输出文件带了min后缀),第二次是未压缩的,最后一次是对各组件分别打包。(PS:我很想给大家用红圈圈在图上标记下,奈何设备不允许。。。数度哽咽......Ubuntu系统下大家有好用的截图标记工具可以推荐下吗?)
开发一个组件
前面扎好了马步,终于到修炼招式的阶段了! 我们都知道,在应用某个插件的时候需要经过下面代码的调用:
好奇下
Vue.use
在做什么处理呢?它其实就是注册/安装这个插件,根据use内部的定义,它通过调用install方法去注册插件,那么,Ange就必须是一个Function
(会被use当做是install
方法调用)或者是一个包含了install
方法的Object
。道理我都懂,可是
install
方法里面到底写些什么?试想一下,我们希望在项目的任意位置都能引用这个插件,那我们的每一个组件是不是要在全局注册?比如通过下面这种方式全局注册组件:
没错,
install
方法内部就是批量地全局注册组件。搭好目录架构
首先我们按照下图的方式新建目录和文件:
在_src目录的index.js_文件中定义
install
方法:核心逻辑install就是对所有的组件循环注册在全局。components目录的_index.js_则是逐个对外暴露组件对象,其次每一个组件也有一个index.js,它的作用是为当前组件注入install方法。理所当然地,
install
里面是将该组件注册在全局,于是我们可以按需引用组件。开发Button组件
组件开发的通用模板
component是vue的内置组件,
is
参数设置成button
,表明最终渲染的html是button
标签,我们也可以直接使用button标签,但我们的按钮组件不一定是button,还可能是a标签,为了更好的拓展,这里使用component。声明组件参数
完善组件模板
剩下的工作就是写好样式表了,你可以选择直接写在vue文件里面,也可以新建_scss/scss_样式表。
组件应用及效果(在线查看)![image](https://user-images.githubusercontent.com/26505680/59194299-28226a00-8bbb-11e9-8236-4013cb614a46.png)
以上,便开发好一个button组件了,执行一下
node build-lib.js
或者npm run build:lib
(现在package.json声明script)就可以打包这个UI框架,然后再将其发布到npm平台(如果你想...)写好一份文档
在线查看 Ange UI Docs 写好文档是一个库不可或缺的部分,写的过程通过实际应用各组件,还可以对其进行测试校验。前面说到,我们的文档要基于vuepress开发,简洁的Markdown写法,很是方便。这里一篇 指南 可以很好地帮助你,它告诉了你如何搭建架构,写好配置以及部署上线,或者参考我这个 仓库 的配置。
假设 docs/views/button.md 是你的
Ange UI内置引入了样式表,这里可以不用再引入,也可以按需只引入
button
组件的文档页面,要如何引用你的组件?button
组件:至此,文档也就写好了!
最后的最后,按照 vuepress doc 部署到你的github仓库上就可以了!
本文通过button组件从0到1的开发,深入浅出阐述了Vue UI框架的开发流程,你对Vue.js的理解越深,组件的功能越复杂,你就会用到更多的高级用法。通过自研UI框架,我们也有很大的收获:
PS:CSS其实是UI开发中占比很重的部分,大家按照自己的风格组件化开发就好。给推荐几个很棒的配色网站: ColorDrop Color Hunt NIPPON COLORS
最后,希望大家也能多多去尝试,这个青铜自研UI库的故事到这里就结束了。
The end.