写在前面
虽然是Vue2组件封装,主要的内容是记录一下我对封装组件的一些要点和我的看法
——原学习视频来源于b站黑马从0到1封装组件库
什么是组件
都说Vue是组件化开发,确实有道理,别说按钮输入框这种组件了,就连每个页面,从本质来看也是一个个组件,所以目标很明确,拿来就能用,有一定使用规范和预设样式,我都认为是一个组件,包括有一定规范和预设样式的页面,也可以认为是一个组件
可以写出什么组件?
关于如何去写自己的组件,我将它分为两块,一块是套路组件,一块是创新组件
- 套路组件
什么是套路组件,为什么我称之为套路?
首先必须知道,无论你使用过哪个组件库,只要是见识过2个及2个以上的同学都会发现,组件库的内容其实大同小异
最常见的正如我上文所提到的按钮和输入框,基本所有的组件库都会有的内容,同时能发现在原Html代码中也可以使用到的相似元素,这样一想,那么组件库中按钮、输入框之类的组件相当于是对原有元素的二次包装。
使用的是已经有的元素,通过预设样式和编写使用文档制作出来的组件,这不就是套路嘛
- 创新组件
既然如此,那创新组件就很显然了,完全使用自己的想法编写出来的组件,不使用默认的元素进行包装
如何去写一个组件
受到一些专讲如何写Vue组件文章的影响,我觉得将编写组件的顺序步骤分为先编写静态页面和后动态交互是非常合理的,我们也应该从这一步出发
编写静态组件
这个其实非常好理解,假设你现在拥有一个非常完整的团队,请UI设计师为你设计一个组件后,你就可以按照组件的基本样子写出来了
这里以 NutUI 为例子,我们看如下图中的按钮,有着非常多的样式
所有的样式都来源于类的切换,而CSS样式正是通过类绑定到元素上,所以在编写静态组件时,需要通过切换类名来制作出不同的样式效果
包括数据展示,静态页面优先使用假数据
动态交互编写
既然已经知道一个页面也相当于一个组件,而一个页面中使用组件时,就等同于父子组件,相对于按钮这种元素,输入框还需要父子间传递数据
- 使用 props 进行父对子传值
父组件书写子组件标签来使用子组件,通过 属性名=“属性值” 的方式来传递数据
子组件中需要写参数 props 来接收,通用组件需要对属性进行约束和校验,当然了约束和校验也可以不写
如下图中该按钮,通过传递一个类型为成功的数据来控制按钮的样式
父组件中:
<apl-button type="success">你好</apl-button>
子组件中:
<script>
export default {
name: "AplButton",
//封装一个通用组件,需要对属性进行约束进行校验
props: {
// 按钮类型
type: {
type: String,
default: "default",
// 自定义验证函数
// type值校验
validator: function (value) {
// 这个值必须匹配下列字符串中的一个
return (
[
"default",
"success",
"primary",
"danger",
"warning",
"info",
].indexOf(value) !== -1
);
},
},
。。。。。。
使用props传值除了直接传值以外也可以通过添加v-bind传递表达式,只要将 type=““改为 :type=””
这里值得一提的是数据应该保存在哪个组件中,相比之下,父组件使用子组件修改了自己的数据比父组件使用子组件修改了子组件的数据听上去更加合理,这也是为什么会有父组件传值给子组件
需要想通的是子在什么时候需要对父传值
即子组件需要修改父组件的值,不过我们知道我们需要遵守子组件不好直接修改数据的原则,所以最好让这个动作由父组件自己来完成,子组件在一旁做个看客这多妙
如下图这个dialog中,父组件的visible值来控制dialog的显示与隐藏,点击子组件的按钮时需要将父组件的visible值变为false来隐藏dialog,自然就不能子组件来改变visible的值,而是将需要改变的值传递给父组件,由父组件来改变visible
父组件中:
<apl-dialog width="80vh" top="20vh" :visible.sync="visible">
<template v-slot:title>标题</template>
点击右上角X关闭这个网页
</apl-dialog>
子组件中:
//下面这行仅展示 X 的代码行
<span class="apl-dialog__headerbtn" @click.self="_handleClose">x</span>
methods: {
_handleClose() {
// 使用sync语法糖
this.$emit("update:visible", false);
},
},
对写好的组件进行装库打包
- 将所有组件放在同一个文件夹package中并新建文件index.js
- 将所有组件引入到index.js中并声明 install 函数依次为Vue注册全局组件
- 默认暴露 install
index.js内容如下
// 整个包的入口
import AplButton from './AplButton'
const components = [
AplButton,
]
// 定义 install 方法,接收 Vue 作为参数,如果使用 use 注册插件,则必须所有的组件都被注册
const install = (Vue) => {
// 遍历注册全局组件
components.forEach(component => {
Vue.component(component.name, component)
})
}
// 判断是否是直接引入文件,如果是,就不用调用 Vue.use()
if (typeof window !== 'undefined' && window.Vue) {
install(window.Vue)
}
export default {
install
}
为package.json中添加命令
// 以下这行为新增
"main":"dist/wad-ui.umd.min.js",
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
// 以下这行为新增命令
"lib":"vue-cli-service build --target lib packages/index.js"
},
使用 npm run lib 命令进行打包动作
生成 dist 文件夹,此时打包已经完成了
接下来将组件库发布到 npm 上
新增文件 .npmignore
# 忽略目录
examples/
packages/
public/
# 忽略指定文件
vue.config.js
babel.config.js
*.map
在终端登录 npm ,没有账号的需要注册账号然后登录
输入命令 后就发布完成了
npm publish
使用自己的组件库
- 输入命令
npm i wad-ui
- 进行全局导入
wad-ui import WadUI from 'wad-ui';
import 'wad-ui/dist/wad-ui.css';
Vue.use(WadUI)
- 愉快的使用自己的组件库
<template>
<div>
<apl-button type="primary" @click="toCheck">确定</apl-button>
</div>
</template>
写在最后
分享一下我的源代码地址
https://github.com/shaoyahu/WadUI
其中有看别人写的抄了点拟态的,不过不是很合我的口味
感谢阅读