前言
很多时候面对日常的工作业务需求,或者面对新项目时往往都是npm i element-ui -S
安装element或者Ant的组件库,但如果自己想要面对特殊的需求需要定制组件往往需要不断修改,改完又往往忘记了整理,最后就是不断的重复。
你所写的每一个 vue 文件都可以视为一个组件,随着业务的不断深入,页面写多了想将组件集合起来封装成一个组件库的想法也不断加剧。仅在此写下组件库的构建思路和历程,供自己记忆学习,也希望能帮助到你。
目录构建
推荐使用@vue/cli 进行项目的构建
npm install -g @vue/cli
-
命令行中输入
vue reate orange_collect
快速初始化一个项目。
将src的目录文件改为examples,用来写组件相关文档和事例。
再新建一个src目录,里面只放一个main.js用来作为打包入口
在根目录下新建一个 packages 文件夹,用来进行组件的编写。
-
在根目录下新建一个vue.config.js文件,配置如下
const NODE_ENV = 'development' // 开发环境 打包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
设置为文件入口。设置examples
和packages
的别名。
此时运行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, ] }, ] })
相关界面如上,需要样式和布局代码可以去我的github上查看,再次不在赘述。
组件编写
常规组件编写
- 我们组件的编写都在packages文件夹中进行,举个(例子),现编写一个测试的button组件。
├─packages │ └─orange_btn #组件模块名称文件夹 │ ├─src │ | ├─orange_btn.vue │ └─index ├─index.js
- 新建一个如上的目录结构,接下来我们就需要在
orange_btn.vue
中编写相关的业务代码。通过props来定义组件的相关组件和状态扩展。export default { props: { type: { type: String, default: "default" }, size: String, icon: { type: String, default: "" } }, name: "orange-button", data() { return {}; },
- 值得注意的是在orange_btn.vue中
name
属性尤为重要它是必须要写的,是判断是否唯一组件的标识,所以你写的应该是不重名的。之后name
将用来判定组件,如这里的name
是orange-button
在之后完
成组件的注册并且最终使用的时候则是
组件图标的引入和使用
- 建议使用iconfont矢量图库将ui的图标上传,或在图标库中寻找合适的图标后,下载至本地。
-
将图中的字体文件夹引入项目
- 在packages文件夹的
index.js
和examples的main.js
中对字体文件进行引入import './assets/font/iconfont.css'
- 使用
iconfont
+类名
组件暴露
-
每一个组件都需要如此步骤,先建立组件同名的文件夹,然后在
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
用来管理,可以避免我们的组件越来越多,需要重复引入,循环安装所有组件。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
中引入
-
使用
已可以在页面中使用,由此可以编写相关的文档说明。
打包配置
- 在项目组件编写过后,就可以将组件打包上传至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的文件。此时文件目录如下。
npm发布
-
npm发布时,要将package.json中的private属性值改为false并修改项目的版本号
- 我们没有必要把所有的代码都发布到npm上。在项目的根目录创建一个.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
- 执行
npm who am i
命令, 如果没有登陆则执行npm login
命令,系统会提示输入账户和密码。如果没有则需要前往npm官网进行注册。 - 登陆之后执行
npm publish
进行版本发布。 - 在npm发布完成之后就可以在任意一项目中使用
npm i orange_collect
来安装项目,之后在main.js
中引入import orange from 'orange_collect' import 'orange_collect/lib/orange_collect.css' Vue.use(orange)
此时的组件均能通过标签正常的使用。
小结
从零新建一个自己的组件库至此就已经完成了,如果想我一样团队中有需要封装自己的组件代码库,则可以试着像我一样写一个轮子一起用,我则是想收集各类有意思的按钮进行自己的封装。github地址