前言
本系列文章旨在告诉读者如何打造属于自己的组件库,面对不同业务以及场景,有着更加灵活可变的应用。当前你必须知道 Vue.js的基础知识以及阅读过Element 组件库常用的组件。
为什么需打造属于自己的 Element 组件库?
接下来我们看一个例子
在我们使用 Element 库时,一定是先调用 el-xxx 组件,然后根据 Element 引入的代码进行渲染进而展现在页面上。想一想这样会有什么问题,如果这时候,有一个新需求,要我们前端需要修改这个组件的样式,怎么办呢?难道我们一个个使用样式穿透,进行修改吗?也许你会想到使用全局样式进行覆盖,我个人是十分反对使用全局样式,因为这样十分不利于代码的阅读以及后期的管理。
可以再举一个极端的例子,现在你有 100 个表格,现在产品经理给你说:“我们的表格要全部根据屏幕大小动态变换高度”。这时候你可能傻眼了,因为 Element 库中的代码是不好修改的,即使修改了,你也难以在别人那生效(所以图上每个 el-select 组件都是独立的)。接下来我们看下一张图:
这一张图中,我们可以看见 el-select组件之前新加了一个 x-select 组件(也就是我们新定义的组件),这个组件中,因为是我们自己定义的,所以我们可以对它进行任意的修改。将来即使组件有什么改动,我们可以直接在 x-select 一处进行修改,前面所有的组件进行全部改动。
总结:自己对 Element 组件库进行封装,就是有一个上层封装,对组件进行一次收束,有一个统一的出口。我们可以根据自己的团队以及业务进行相应的定制,以满足前端定制化以及快速开发。
重点知识(必须)
打造组件库我们肯定需要使用到组件之间的通信,组件一般会使用到父向子通信、子向父通信、非父子组件通信(使用 bus 或者 Vuex)、依赖注入通信(简单来讲就是祖先组件向后代组件进行通信),在这里我们就先简单介绍下父向子通信、子向父通信(若有更好的讲解,欢迎评论区提出)。
父向子通信 props
父向子通信,我们只需要在父组件中子组件的实例上,添加上要传递的参数,最后再子组件中的 props 属性中声明即可接收。一个简单的小 demo 如下:
articleList 是我们的父组件,而 editArticle 是我们的子组件。我们在 articleList 父组件中使用了 editArticle 组件的实例,并且传递了 articleInfo 这个参数。然后我们在editArticle 组件中 props 处进行了接收。
看懂这些并不难,但是有些小伙伴可能会没有见过 props 这里的写法,你们可能平常是运用的是数组写法。数组写法虽然更加简单,但是可配置项没有,推荐还是对象写法。
// 数组写法,简单但是没有可配置项
props: ['articleInfo']
// 对象写法,可进行配置,由于场景过多,将用 propA、propB...进行说明
props : {
// 必须是数字类型
propA: Number,
// 必须是字符串或数字类型
propB : [String, Number] ,
// 布尔值,如果没有定义,默认值就是 true
propC: {
type : Boolean,
default : true
}
// 数字,而且是必传
propD: {
type: Number,
required: true
}
// 如果是数组或对象,默认值必须是一个函数来返回
propE: {
type : Array,
default : function () {
return [];
}
}
// 自定义一个验证函数
propF: {
validator: function (value) {
return value > 10;
}
}
}
其实有一点 Vue 基础的小伙伴们看懂这些知识其实并不难,但是其中也是有一些需要注意的点。
- props 的值尽可能只用来只读,当我们去修改 props 上的值,Vue 会进行报错,当我们修改的是 Object 类的值时,虽然 Vue 不会检测到你进行了修改,但是这种情况还是避免(除非是你故意这样的)。我们通过会使用 data 里的变量去接收下 props 里面的值,如果这是个 Object 类的值,我们则需要进行深拷贝。数组推荐使用 slice,对象推荐使用 Object.assign。
- 父子通信并不是立马就会完成的,有时候我们父向子通信后,马上利用 ref 调用子组件中的值,发现并没有生效,这其实是通信需要一定时间,我们需要等待一下。我们可以使用$nextTick或者 setTimeout 进行等待,这两者有什么区别就不再赘述了。
子向父通信 emit
子组件用$emit()来触发事件,父组件用$on()来监昕子组件的事件,父组件也可以直萨在子组件的自定义标签上使用 v-on 来监昕子组件触发的自定义事件。上一个小 demo :
在这里,我们在 assnDetails 组件中定义了一个 btnForm 组件在上面使用 v-on 来监昕了自定义事件 submit 和 reset。
然后我们在 btnForm 组件进行相关的触发事件,第一个方法 cancel 方法触发 reset 自定义事件,第二个方法 apply 方法触发 submit 自定义事件(当前cancel、apply都在本页面都是通过按钮点击触发,你也可以设置其他的,这里并不重要)。
触发自定义事件后,父组件收到,然后会执行相应的方法,比如触发自定义事件 submit 执行的方法就是 applyAssn(由一图可知)。
子向父通信,多多使用几次其实也会很好理解,不过我们还是得注意,自定义事件不要和 click 等原生事件重名。
$attrs、$listeners
- $attrs
该属性可以获取到父组件传过来的所有属性
- $listeners
该属性可以获取到父组件传过来的所有事件
一个 demo 看懂所有:
这是我们定义的一个按钮组件,但是我们也想使用 Element 按钮组件的相关东西,但是 Element 按钮组件的属性以及事件非常多,我们一个个传递十分麻烦,有没有什么一劳永逸的方法呢?$attrs、$listeners就是用来解决这个问题的,它可以把我们自定义的组件上设置的属性以及事件一起丢给 Element 组件。我们还可以对它进行一次拦截,给它设置默认值等等。这是我们后续经常会用上的属性。
后续
这是一个作者新开的系列,旨在分享自己封装组件的心得以及经验,欢迎一起讨论。也请关注后续。。。