组件化是长期开发过程当中一个提炼精华的过程,目的主要是如下几点:前端
那么如何达到这样的效果呢,咱们能够分几步来按部就班地完成。vue
下文主要是思路,想直接获取代码可转战ElementUI的Github去看源码webpack
组件从大类上能够分为两种:git
基础组件的颗粒度争议并不大,就是Button,Table等等 业务组件的颗粒度最大能够为一个feature,一个feature就是一个能够独立上线特性,例如文章的评论点赞功能。咱们能够想象有一个开关,打开就有这个feature,关闭就没有,且不会形成联动的影响。github
UI规范是组件开发的物理依据,你得知道要作成什么样子,你才能作。UI规范要对整套组件的各个视觉元素(长,宽,padding,margin,圆角,颜色,字体,字号,边框,图标,阴影)有语意明确的定义和友好的标注,这样前端工程师们才能作到有法可依。web
举例:
1.sass或less来写样式
2.重置样式文件和样式的公共变量文件(将视觉元素翻译成代码中的常量造成的文件),这是根据本身的UI规范来决定的
3.ES6的哪些特性不使用,用哪个stage的babel来翻译
4.须要引入的第三方包有哪些,这个也决定了最后打包出来组件js的大小
5.工程的目录结构
复制代码
对于Vue,咱们一般使用的是webpack。具体配置这里不详细讲解,能够参考入门Webpack,看这篇就够了,还有一个快速方法就是经过Vue-cli生成的模板工程来进行更改。 接着咱们要定义清楚咱们的打包策略:设计模式
举例:
1.全部的样式打到一个文件
2.有fonts则单独打出来
3.组件JS和VueJS不打在一块儿
4.非通用的第三方包需和组件打在一块儿
复制代码
以上四点是正式编写组件代码的前置工做。如今咱们经过elementUI的源码来看一个最佳实践,咱们的例子是比较简单的面包屑,先看一下怎么去使用的这个组件: api
<template>
<span class="el-breadcrumb__item">
<span class="el-breadcrumb__inner" ref="link" role="link">
<slot></slot>
</span>
<i v-if="separatorClass" class="el-breadcrumb__separator" :class="separatorClass"></i>
<span v-else class="el-breadcrumb__separator" role="presentation">{{separator}}</span>
</span>
</template>
<script>
export default {
name: 'ElBreadcrumbItem',
props: {
to: {},
replace: Boolean
},
data() {
return {
separator: '',
separatorClass: ''
};
},
inject: ['elBreadcrumb'],
mounted() {
this.separator = this.elBreadcrumb.separator;
this.separatorClass = this.elBreadcrumb.separatorClass;
let self = this;
if (this.to) {
let link = this.$refs.link;
link.setAttribute('role', 'link');
link.addEventListener('click', _ => {
let to = this.to;
self.replace ? self.$router.replace(to)
: self.$router.push(to);
});
}
}
};
</script>
复制代码
props中就是ElBreadcrumbItem暴露出来的两个接口,也就是上文第三点提到的内容,接口的值是从父组件传过来的。咱们再看一下ElBreadcrumb,也就是父组件的代码实现。sass
这里简单解释一下inject:inject和provide是成对出现的,是vue@2.2.0的新特性。经过此种方法变能够直接调用提供provide的组件中的属性了,总结就是依赖注入(DI)。bash
<template>
<div class="el-breadcrumb" aria-label="Breadcrumb" role="navigation">
<slot></slot>
</div>
</template>
<script>
export default {
name: 'ElBreadcrumb',
props: {
separator: {
type: String,
default: '/'
},
separatorClass: {
type: String,
default: ''
}
},
provide() {
return {
elBreadcrumb: this
};
},
mounted() {
const items = this.$el.querySelectorAll('.el-breadcrumb__item');
if (items.length) {
items[items.length - 1].setAttribute('aria-current', 'page');
}
}
};
</script>
复制代码
slot实际上是专门留给ElBreadcrumbItem的插槽,实际上ElBreadcrumb不涉及什么UI,它也经过props暴露出来了两个接口,这个两个的值是使用者传入的。咱们能够看到,默认的分隔符是'/',若是你在ElBreadcrumbItem中经过属性传入的分隔符是'+',那面包屑每一级中的分隔符也会是'+',注意一下代码中的provide和上面的inject相对应。最后就是让组件可注册
import ElBreadcrumb from './src/breadcrumb';
/* istanbul ignore next */
ElBreadcrumb.install = function(Vue) {
Vue.component(ElBreadcrumb.name, ElBreadcrumb);
};
export default ElBreadcrumb;
复制代码
经过给组件添加install方法,让组件可被Vue.use方法在全局注册。可参考Vue官方文档API
本文简单梳理了一下组件开发的思路,重点在于组件开发的这些前置条件:
完成这几点,从代码层面只是一小部分工做,但若把整个组件做为一个产品来看,就已经完成了一半了。