前言
作为一位有追求(但学不动)的前端开发者,我们肯定都曾想通过看组件库的源码(本章以 Element 为例)来拔高自己的水平,也肯定都尝试过,只是最终不了了之罢了。就像我也是这样的?,到现在也只看了 1/6 ?,还是最简单的那几个组件。其实(对于功底一般的我们来说)看源码是需要时间和方法的:关于时间,我想每个星期(看自己安排)看一个组件就足以,不用全部看完,挑有代表性的看就行;关于方法就是我本章要重点讲解的,这里以 button 组件为例(因为它最简单实用),希望你看完之后能够有所启发。当然啦,看源码之前其实还有一件很重要的事情要做,就是你应当要用过 Element 之类的组件库,这点很重要,要先学会用,再去深究其原理。就像我给你一把锯子(真是个凑合的比喻?),你不曾用过它,就想去搞懂锯子是怎么做的,你说你都不知道它的实际应用场景,又怎么去设计好它呢,靠天马行空么。
哦,对了,鸡汤一下,其实源码这东西只是听起来玄乎,看起来迷茫,你只要稍微熟悉之后,它就变得很透明了,任你?宰割(解读)。很多东西只是我们平时碰的比较少,因为陌生所以才觉得难。想想我们平时开发过程中写的组件,那个也是源码啊,只不过写的可能没有那么优雅罢了???。
Element 源码地址:github.com/ElemeFE/ele…
Element 文档:element-cn.eleme.io/#/zh-CN/com…
关于目录
由于本文的重点是讲解组件的具体思路,所以我们只要知道组件源码在哪里就行了,至于整体目录就结构先不说了,当然了,有兴趣的同学们可以看一下?这篇文章:?: 基于 vue-cli3 打造属于自己的 UI 库 。怎么看
这里先简要说下我看组件源码的方法,仅供大家参考,不喜勿喷哈?。
首先 Element 有几个版本,我看的是基于 Vue 的版本,所以每个组件到底就是一个 vue 文件,就和我们平时工作写的代码一样,写好一个 vue 组件,然后在需要的页面引入即可。不过更重要的是要知道如何写好这个组件(健壮吗,可扩展吗,易维护吗等)。一个 vue 组件一般可分为三部分,template
、script
和 style
。在这里我们就不考虑 style
了,直接在页面引用 Element 的样式就好,因为这不是我们主要关心的,我们只要知道 Element 的样式一般是这样(el-组件名--状态
,比如 el-button--primary
)命名的就行。所以我们组件里是没有写 style
部分的,这样做能帮我们省下好多时间和精力。
// 直接在页面中引入 Element 的样式
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
复制代码
先看 template 部分
那么接下来我们就先看看 template
的部分怎么写。其实这部分是很简单的(对于这个组件来说?),我们可以先打开 Element 文档看一下 button 的外观样式,再来写这部分,它大概长下面这样:
html
结构的公共部分),大概就是一个
div
(button 标签)里面包了一个
i
图标和
span
文本这样的结构,嗯好像是这样,那就试着写一下吧!(提示:Element 组件一般最外层的样式都是用
el-组件名
包起来的)
<template>
<button class="el-button">
<i></i>
<span></span>
</button>
</template>
复制代码
看上面的结构像那么回事,也简单明了。不过,然后呢?。。。 然后就是我们的 script
部分啦,这个才是组件的灵魂所在,重中之重,也是需要我们去啃的部分。好在这个组件简单,让我们继续往下看吧。
再看 script 部分
我们看这部分的时候,可能无从下手,但其实还是有点门道的。敲锣啦???。。。。不管神马组件,都有三个较为重要的组成部分:props
、event
和 slot
,这三个部分是组件对内对外沟通的桥梁,使得组件变得灵活起来。所以这三个 api 在发布之前一定构思好和确定好,因为后期再改就很难了,可能就是会牵一发动全身那样子。但后期对组件的处理其实不应该是这样的效果,而应该是不影响和改动之前的 api,但又可以扩展和新增功能。ok?,就让我们一个一个娓娓道来吧?。 首先看下 props
的部分,你需要在脑海中想象一下 button 组件的哪些内容是可变的(根据需要外部传参的改变而改变),不用着急往下看,先好好想一下?。。。。
...
1)最明显的就是 button 的背景色吧,这显然是可变的,就是 type;
2)然后是有没有图标,就是 icon;
3)还有就是有没有禁用,就是 disabled;
4)再来是有没有圆角,就是 round;
5)尺寸大小也是可变的吧,就是 size;
6)好像按钮还可以是文本的样子,就是 plain;
....
好了,那我们就试着写一下 props
部分吧!(注意:props
的部分最好用对象的写法,这样能够对每个属性进行自定义设置,相比数组的写法,更为规范严谨)。
<script>
export default {
props: {
type: {
type: String,
default: ''
},
size: {
type: String,
default: 'medium'
},
icon: {
type: String,
default: ''
},
disabled: Boolean,
plain: Boolean,
round: Boolean
}
}
</script>
复制代码
接下来是 slot
部分啦,如果不懂 slot
用法的同学可以先出门左拐学习一下再来✋。很明显,对于 button 组件来说,文本就是 slot
啦,所以 template
里面的内容可以小改一下,代码如下:
<template>
<button class="el-button">
<i></i>
<span><slot></slot></span>
</button>
</template>
复制代码
然后是 event
部分,很显然啦,按钮能有什么功能呢,就是点击嘛,没了,所以它也就一个事件,就是当按钮被点击的时候,我们需要触发一个事件向上传递,也就是 $emit
。于是乎,我们把事件添加到组件中,代码如下:
<template>
<button
class="el-button"
@click="handleClick">
<i></i>
<span><slot></slot></span>
</button>
</template>
<script>
export default {
props: {
...
},
methods: {
handleClick (e) {
this.$emit('click', e);
}
}
}
</script>
复制代码
好像 event
的部分就那么多,嗯,是的,比想象中的简单✊。。。。
再看 template 部分
你以为组件写完了,不,并没有,你不觉得 template
里面太空了么,而且 props
这部分的属性都还没用上呢(只是声明了一下),所以我们还需要完善点东西。。。 比如 slot
部分吧,通过 $slots.default
我们可以获取到 slot
中的内容,不过这里需要加个判断,因为用户可能没有传文字,那我们就不用渲染了; 又比如图标 i
的部分,和 slot
一样,有传值我们才渲染,所以也加个判断(这里 icon 的值为 el-icon-图标名
格式)。
<template>
<button
class="el-button"
@click="handleClick">
<i :class="icon" v-if="icon"></i>
<span v-if="$slots.default"><slot></slot></span>
</button>
</template>
复制代码
再看 props
中的属性,其实当中大部分都是用来控制样式变化的,比如 type
,size
,round
,disabled
,plain
等。。。所以就让我们为组件加上些 class
吧。
<template>
<button
class="el-button"
@click="handleClick"
:disabled="disabled"
:class="[
type ? 'el-button--' + type : '',
size ? 'el-button--' + size : '',
{
'is-disabled': disabled,
'is-plain': plain,
'is-round': round
}
]">
<i :class="icon" v-if="icon"></i>
<span v-if="$slots.default"><slot></slot></span>
</button>
</template>
复制代码
至此我们就写完了一个较为完整的 button 组件,是不是给人一种?这么简单的么?的感觉,虽然它还不够完善,但也覆盖了源码 90% 的部分,剩下的 10% 大家可以自己去补充补充。其实组件主要还是要看你?思考?得有多全面,想的越多写的越多。
结语
顺着上面的思路,我们就可以有个较为明了的方法去看 Element 其他组件的源码(应该会轻松一些吧?)。当然这里仅仅只是起一个抛砖引玉的作用,主要还是因为 button 组件确实简单还实用,很适合敲门砖的角色,当然也许后面看到其它复杂的组件你就不会这样想了?。但是不管怎么说,好的开始是成功的一半,革命尚未成功,同志仍需努力。撸起袖子加油干吧?!!!