Dear,大家好,我是“前端小鑫同学”,😇长期从事前端开发,安卓开发,热衷技术,在编程路上越走越远~
现在其实做的不错的开源 UI 库有很多,我还没有真正的实践过多造一个轮子也没太大必要,但是学习编写的思路和过程还是很有必要的,正好看到慕课的一个视频就顺便总结一下组件库开发的流程,顺便熟悉一个打包的配置和流程。
vue create it200-ui
;cd it200-ui
,并启动yarn serve
;src/components
层级到根目录;src
为组件渲染示例examples
;pages
节点来更改入口;目录结构如下,需按要求安装开发依赖sass-loader
,为了避免与 node-sass
的版本冲突造成得更多问题,我们不再安装它而去添加一个名为sass
包;
components
├─lib
| ├─demo
| | └index.vue
├─css
| └demo.scss
在示例文件夹得 main.js 中导入并申明组件:
import "../components/css/demo.scss";
import Demo from "../components/lib/demo/index.vue";
Vue.component("name", Demo);
通常在使用开源 UI 库时并没有使用 component
来导入组件,而是使用的 use
进行安装,所以我们在组件的同目录创建一个组件的安装脚本:
import Demo from "./index.vue";
Demo.install = function (Vue) {
Vue.component(Demo.name, Demo);
};
export default Demo;
import Demo from "../components/lib/demo/index.js";
Vue.use(Demo);
组件的设计一定是为了满足多处的复用而提出来的,站在各自的角度也可能都会有不一样的答案,所以我们这里找了 Element 的 card 组件中的一块内容来充当我们今天待设计组件的需求:
卡片组件需要满足以下几点要求,其他的要求暂不考虑:
参数 | 说明 | 类型 | 可选值 | 默认值 |
---|---|---|---|---|
body-style | 设置 body 的样式 | object | — | { padding: '20px' } |
shadow | 设置阴影显示时机 | string | always / hover / never | always |
components/
├─lib
| ├─card
| | ├─index.js
| | └index.vue
├─css
| └card.scss
import "../components/css/card.scss";
import Card from "../components/lib/card/index.js";
Vue.use(Card);
通过 props 提供组件的上述基础属性。
export default {
name: "it-card",
props: {
bodyStyle: {
type: Object,
default: () => {
return { padding: "20px" };
},
},
shadow: {
type: String,
default: "always",
},
},
};
组件的大致结构如下,通过三层 div 来设置卡片组件容器、阴影、内容区的样式,并提供默认插槽来设置具体内容。
<template>
<div class="it-card">
<div :class="`is-${shadow}-shadow`"></div>
<div class="it-card__body" :style="bodyStyle">
<slot></slot>
</div>
</div>
</template>
.it-card {
border-radius: 4px;
border: 1px solid #ebeef5;
background-color: #fff;
overflow: hidden;
color: #303133;
transition: 0.3s;
.it-card__body {
padding: 20px;
}
.is-always-shadow {
box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
}
.is-hover-shadow:hover {
box-shadow: 0 2px 12px 0 rgb(0 0 0 / 10%);
}
.is-never-shadow {
box-shadow: none;
}
}
在 app.vue 中完善卡片组件,并对比组件设计稿。
<template>
<div id="app">
<h3>Card组件</h3>
<it-card style="width: 300px" :body-style="{ padding: '0px' }">
<img
src="https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png"
class="image"
/>
<div style="padding: 14px">
<span>好吃的汉堡</span>
<div class="bottom">
<time class="time">"2022-05-03T16:21:26.010Z"</time>
</div>
</div>
</it-card>
</div>
</template>
<script>
export default {
name: "App",
};
</script>
<style>
// 这里的样式使用 element card 使用的样式
</style>
在前端模块化的进程中,经过了全局函数、命名空间,匿名函数自调,文件模块化方案,尤为常见的文件模块化方案就是 CommonJs,ADM,UMD 了,下面来介绍一下各自的特点;
结论:CommonJs 的模块更适用于服务端应用。
结论:AMD 的模块更适用于浏览器端应用。
exports
来确认是否支持 Node.js 模块;define
来确认是否支持 AMD 模块;window
或 global
)。webpack.components.js
:const glob = require("glob");
let entrys = {};
async function makrList(dirPath, list) {
const files = glob.sync(`${dirPath}/**/index.js`);
for (let file of files) {
const component = file.split(/[/.]/)[2];
list[component] = `./${file}`;
}
}
makrList("components/lib", entrys);
复制代码
const path = require("path");
module.exports = {
entry: entrys,
output: {
filename: "[name].umd.js",
path: path.resolve(__dirname, "dist"),
library: "it200",
libraryTarget: "umd",
},
};
复制代码
.vue
的文件我们需要使用对应的loader来处理,Vue 文件对应的就是vue-loader
,需要注意的是我们目前基于 Vue2 来构建的项目,所以最新的vue-loader
并不是特别适合我们可以降级到 **15**
版本来让构建正常进行。const { VueLoaderPlugin } = require("vue-loader");
module.exports = {
plugins: [new VueLoaderPlugin()],
module: {
rules: [
{
test: /\.vue$/,
use: [
{
loader: "vue-loader",
},
],
},
],
},
};
复制代码
"build:js": "webpack --config ./webpack.components.js"
复制代码
在 lib 目录下新建一个index.js 文件将我们的组件统一导入后统一执行组件挂载。
import Demo from "./demo";
import Card from "./card";
const components = {
Demo,
Card,
};
const install = function (Vue) {
if (install.installed) return;
Object.keys(components).forEach((key) => {
Vue.component(components[key].name, components[key]);
});
};
export default {
install,
};
复制代码
gulp 主要通过定义任务并使用流式的处理方式使用不同的管道依次进行,我们主要处理 scss 文件内容为 css 文件。
dist/css
目录下;"build:css": "npx gulp sass"
。const gulp = require("gulp");
const sass = require("gulp-sass")(require("sass"));
const minifyCSS = require("gulp-minify-css");
gulp.task("sass", async function () {
return gulp
.src("components/css/**/*.scss")
.pipe(sass())
.pipe(minifyCSS())
.pipe(gulp.dest("dist/css"));
});
复制代码
在 css 目录新建 index.scss 文件,并将各个组件需要的 scss 文件导入到此文件。
@import "./card.scss";
@import "./demo.scss";
复制代码
import "../dist/css/index.css";
import IT200UI from "../dist/index.umd";
Vue.use(IT200UI);
复制代码
import "../dist/css/card.css";
import Card from "../dist/card.umd";
Vue.use(Card);
import "../dist/css/demo.css";
import Demo from "../dist/demo.umd";
Vue.use(Demo);
复制代码
完成新增内容如下:
{
"description": "IT200 组件库,最小原型演示",
"main": "dist/index.umd.js",
"keywords": [
"it200",
"ui",
"组件库"
],
"author": "fe-xiaoxin",
"files": [
"dist",
"components"
]
}
复制代码
npm i it200-ui
复制代码
// 全部引入
import 'it200-ui/dist/css/index.css';
import IT200UI from 'it200-ui';
Vue.use(IT200UI);
// 按需引入
import 'it200-ui/dist/css/cart.css';
import { Card } from 'it200-ui';
Vue.use(Card);
复制代码
nrm
包进行源的管理,可以通过 nrm ls
查询和 nrm use
进行切换;npm login
开始登陆,分别输入用户名、密码、邮箱,开通动态验证的话还需要输入动态验证码,开通的方式可以翻我以前的文章;npm publish
开始发布,开通动态验证码的话需要再次验证动态验证码;     整个组件库的开发我们省略了最后一步,因为版本的问题导致 vuepress 没有成功的配置,在开发组件库的过程中使用到的技术栈可以是五花八门但是通过本次总结到的我们开发组件库的生命周期大致统一应该是搭建结构、设计组件、编写组件、验证组件、打包构建、发布为主线,构建组件库文档站点、编写使用手册、自动化构建发布为支线同步进行。