Element 是由饿了么UED设计、饿了么大前端开发的一套基于 Vue 2.0 的桌面端组件库。今天咱们要分享的就是开发 Element 的一些心得。css
官网:http://element.eleme.io/#/
github:https://github.com/ElemeFE/element前端
大部分项目起源都是源于业务方的需求,Element 也是同样。随着公司业务发展,内部开始衍生出不少后台系统,UED 部门也接到愈来愈多的设计需求,分析整个过程,咱们发现以下问题:vue
- 日渐增多的后台产品设计需求
- 设计资源有限,没办法支持全部业务线
- 公司内部诸多后台产品使用体验不一致node
因而咱们决定:react
- 设计一套后台支撑框架,提高后台系统的可用性和一致性
- 套用此框架,即便没有设计师参与,也能让产品或开发设计出一套好用的后台系统webpack
下面简单说一下设计 Element 经历的几个阶段。laravel
**了解业务并熟悉公司内各后台产品,寻找业务上的共性问题**
设计的目的是为了业务服务。第一步咱们从内部系统开始入手,了解公司内部在使用的各类后台系统,将其组件抽象剥离,寻找共性特征。git
**专一业务组件设计**
总结了公司不一样系统不一样组件的使用状况后,咱们打算从业务组件入手,由于这部份是由公司特殊需求衍生的解决方案,咱们认为解决了这些棘手的问题,也能给其余后台产品带来好的设计引导。github
**寻求开发支持**
到这一步,咱们开始寻找公司内部的开发团队,并在这时才得知不一样团队里使用着不一样的前端框架,有 Vue、React、Angular 等等。web
**与大前端合做**
大前端做为独立的前端团队,有能力开发底层的工具去服务不一样业务,而且 Vue 也是一套年轻且发展方向很好的一个技术栈。UED 与大前端的合做一拍即合。
**方向转变,专一于基础组件**
跟大前端接触后,才发现最开始的方向并不正确,由于业务变化过快,即便有通用的业务组件,也很难跟上需求的变化,而基础组件才是全部开发团队都须要的通用组件。这时候咱们开始把方向调整为基础组件的设计。
**组件交互完成,进行视觉封装,并搭建主体网站**
前期的设计工做主要是由交互设计师进行设计,等确认完全部组件的功能和交互后,开始进行视觉阶段,这中间包括制定颜色、字体等各种规范,也同时进行主体网站的设计。
输出 UI Kit 文件,统一设计规范
初版网站设计,此处的「特殊组件」即业务组件。
**网站二次设计**
初版网站上线后视觉效果并很差,咱们内部进行了调整,再次上线后就是你们如今看到的样子。
设计过程简单来讲就经历了这几个阶段,如还有问题能够继续交流,下面进入开发阶段。
- 后台系统缺少一套完整的基础组件库
- Vue 在公司内部是一个比较年轻的技术栈,但愿作一些基础设施的建设
- 提高公司在技术社区的影响力
进入开发阶段后,在整体架构方面咱们作了一些尝试,下面按照时间顺序分享给你们:
**如何与设计师进行配合**
通过项目初期开发和设计的磨合,咱们提炼了一套组件开发流程:
1. 根据交互稿和视觉稿进行开发,期间与设计师保持沟通
2. 开发完成后自测,以后提交设计师验收
3. 设计师提出修改意见,根据意见进行修改
4. 完成组件开发,为网站编写例子和文档
**如何管理多组件项目**
在开发之初,咱们就在思考如何下降组件的耦合度,确保组件能够独立工做。这样的目的是能够保证组件能够依赖其余组件、让用户只加载其中几个组件甚至在安装时只安装须要的组件。最早想到的作法是一个组件单独一个仓库,而组件库项目就是把组件做为依赖引入。
可是因为人手不足,这样的机制致使开发太耗时间,每一个组件都须要单独维护和打包,同时还要维护组件库项目的各依赖的版本号。咱们只能另寻方案。后来参考了 [babel](https://github.com/babel/babel) 项目的管理方式:全部子项目放在 `packages/` 目录里,一个子项目能够看成一个独立的仓库。经过 [lerna](https://github.com/lerna/lerna) 来管理子项目的依赖和发布。
结合自身项目的特色以及 babel 的这套机制,咱们重构了目录结构:组件可单独做为一个项目放在 `packages/`,共用函数放在 `src/` 里。最后的打包结果会将整个组件打包成一个文件、组件分别打包成独立文件,同时发布时还将发布组件库和独立组件,知足不一样用户的使用需求。
**如何解决自定义主题**
开发一套组件库就离不开定制主题的需求。类名要足够友好,尽可能避免存在样式层级嵌套,这样在直接覆盖样式或者单独写一套主题都会方便许多。因此咱们采用 BEM 的方式管理类名,同时尽量将属性值用变量代替,维护一份变量文件便于直接修改变量就能定制一套主题。
考虑到不一样用户的使用习惯,咱们没有选用 Less 或 Sass 之类的有各自风格的预处理器,而是选用了更接近将来标准的 CSS4 风格的语法,用 PostCSS 和整合了 postcss-bem 和 postcss-cssnext 等插件的 [postcss-salad](https://github.com/ElemeFE/postcss-salad) 开发。
为了下降用户自定义主题的上手成本,咱们还提供了命令行工具指导用户快速自定义一套主题。
**如何提供一份直观的文档**
文档不只是让用户看起来直观,也要让编写者写起来直观。因此最简单的方式是用 Markdown 写文档。可是就会产生另外一个问题:如何在文档里写可运行的示例?常规的作法是把文档写在 Vue 文件里,这样就能够在里面调用其余组件,可是这样就违背了写「直观」文档的初衷。
通过几番尝试,结合 Vue 的特色。咱们写了一套处理 Markdown 文件的 webpack loader,能够将 Markdown 转成 Vue 文件,不只下降了文档的维护成本,同时也将文档里运行组件示例变成可能。
**多语言官网如何配置和管理**
Element 在立项之初其实并无考虑国际化的问题。项目开源以后,咱们陆续收到了一些外国开发者的反馈,但愿可以增长英文文档。不久以后,国内的一个翻译团队主动联系到了咱们,为 Element 贡献了整套英文文档。
有了英文文档就须要有英文网站,这就须要对官网的现有结构进行修改和升级;同时为了面向将来,须要官网可以兼容除英语外的其余多语言。为此咱们作了如下工做:
1. 路由
官网的路由是根据一个记录了导航信息的 `json` 文件自动生成的。所以须要在这个 `json` 文件中添加对应于其余语言的字段,而且根据新的数据结构修改路由生成的逻辑。
2. 页面
官网中除了文档外,还有一些介绍性质的页面。这些页面中文字比较多,若是人工管理每种语言的页面,若须要修改则必须去每一个页面相应的位置进行编辑,有些繁琐。咱们的作法是:每一个页面对应一个模板,模板中的文字所有抽取到一个语言配置文件中,而且写了一个脚本生成最终的页面。这样在须要修改时,只需在语言配置文件中编辑对应的字段便可。
3. 网站组件
对于 `header` 、`footer` 等通用的页面组件,咱们采起了和上面相似的策略。但因为组件内的文字较少,因而没有再使用模板,而是经过路由判断应该显示何种语言。
中英文网站的显示效果
至此,咱们也逐渐完善了技术栈。用 ES2015 和 CSS4 做开发语言、Lerna 负责管理组件、用 Karma 搭配 Mocha 和 Chai 等工具在 Travis CI 里作持续集成测试,最后用 Markdown 结合 Vue 写文档。咱们甚至还在 CI 里实现了自动部署网站和推送主题仓库代码等功能,提高了很多开发效率。
具体到组件层面,在开发的过程当中不可避免地会遇到一些问题。下面是咱们的一些应对策略,但愿可以抛砖引玉,引起你们的思考和讨论。
在 Vue 2.0 中,用于父子组件间事件通讯的 `$dispatch` 和 `$broadcast` 被移除了。官方的考虑是,基于组件树结构的事件流方式让人难以理解,而且在组件结构扩展的过程当中会变得愈来愈脆弱。可是相似 Element 这样的组件库有几个特色:首先,父子组件间互相通讯的场景很是常见,好比在一个带有验证功能的表单里,每一个表单项在 `change` 或 `blur` 时须要通知表单组件进行校验;其次,组件的结构相对来讲比较固定。
出于以上考虑,咱们实现了简化版的 `dispatch` 和 `broadcast` ,并把它们包装成了一个 `mixin` ,方便在须要时调用。其中的 `dispatch` 代码以下:
dispatch(componentName, eventName, params) {
var parent = this.$parent || this.$root;
var name = parent.$options.componentName;
while (parent && (!name || name !== componentName)) {
parent = parent.$parent;
if (parent) {
name = parent.$options.componentName;
}
}
if (parent) {
parent.$emit.apply(parent, [eventName].concat(params));
}
}
能够看出,咱们的实现须要在调用时传入 `componentName` (在各个组件中定义),这样就确保了事件只会在正确的组件中触发。
在 Vue 2.0 中的自定义组件上使用 `v-on` 只会监听自定义事件(即组件用 `$emit` 触发的事件)。若是要监听原生事件,必须使用 `.native` 修饰符:
<mt-component @click.native="handleClick"></my-component>
这样一来,不少不太熟悉 Vue 2.0 语法的用户会发现给 Element 的组件绑定原生事件老是不生效。事实上,咱们从开源以来收到的 issue 里被问得最多的一个问题是:如何给 `Button` 组件绑定 `click` 事件?
事实上咱们只须要添加一行代码就能解决问题,可是关因而否须要让用户能够直接监听原生事件这件事在咱们内部有两种不一样的观点:一边认为应该遵循 Vue 的设计思想,原生事件要加 native;另外一边认为 button 最经常使用的就是 click 事件,帮助用户作这件事能够下降学习成本。后来咱们专门咨询了尤雨溪本人,他的观点是,对于一些组件的经常使用事件,能够容许用户直接监听原生事件,同时在文档中说明哪些事件能够直接监听,哪些事件须要加 `.native` 修饰符。最后咱们决定从易用性的角度出发,让用户在使用 `Button` 组件时能够监听原生 `click` 事件,由于对于桌面端来讲,`Button` 在绝大部分场景下都是须要监听点击事件的。 如今的 `Button` 支持如下两种写法:
<el-button @click.native="handleClick">Click Me!</el-button>
<el-button @click="handleClick">Click Me!</el-button>
在历次迭代中,咱们会尽可能保持 API 的一致。可是在一些万不得已的状况下,须要对 API 做出一些更新。对于老版本的用户而言,若是使用了被移除的 API,升级到新版后会出现一些意料以外的报错信息。为了友好地帮助用户尽快找到报错的来源,咱们编写了一个 `mixin` ,当组件的 API 发生变化时,在组件中引入这个 `mixin` 并列出变化先后的字段名便可。
`mixin` 的核心代码为:
const { props, events } = this.getMigratingConfig();
const { data, componentOptions } = this.$vnode;
const definedProps = data.attrs || {};
const definedEvents = componentOptions.listeners || {};
for (let propName in definedProps) {
if (definedProps.hasOwnProperty(propName) && props[propName]) {
console.warn(`[Element Migrating][Attribute]: ${props[propName]}`);
}
}
for (let eventName in definedEvents) {
if (definedEvents.hasOwnProperty(eventName) && events[eventName]) {
console.warn(`[Element Migrating][Event]: ${events[eventName]}`);
}
}
引用了这个 `mixin` 的组件须要在 `methods` 中添加一个名为 `getMigratingConfig` 的方法,返回一个包含发生变化的 API 字段名和对应提示信息的对象:
getMigratingConfig() {
return {
props: {
'selection-mode': 'Table: selection-mode has been removed.'
},
events: {
cellclick: 'Table: cellclick has been renamed to cell-click.'
}
};
}
咱们选择使用 Tower 来配合 GitHub 进行 issue 的追踪和处理。首先在 Tower 上创建几个清单:Plan、Design、Develop 和 Release。随后具体的操做流程以下:
- 从各渠道收集反馈
- 若不需设计,则由开发回复
- 若需设计跟进,则在 GitHub 上添加标签 `design` ,并在 Tower 的 Plan 清单中添加相应任务
- 开始处理任务后,为 GitHub 的对应 issue 添加 `working in progress` 标签,同时把任务拖进 Tower 的 Design 清单
- 设计完成后,开发接手,同时把任务拖进 Develop 清单
- 开发完成,通过设计师验收经过后将改动推送至 GitHub 仓库,关闭相应 issue,最后将任务拖进 Release 清单
Element 从立项至今已经走过了五个月的时间。总的来讲,这段时间就是一个不断发现问题和解决问题的过程,也是每一个参与者自身成长的过程。开发时 Vue 2.0 正处于 RC 阶段,咱们随着它的版本迭代踩到了很多坑,同时也给 Vue 提了一些 issue,而且都获得了 Vue 团队的处理。在此向Vue 团队的专业精神表示感谢。
自从 9 月开源以来,在社区的帮助下,Element 逐渐成熟,咱们也在今天发布了它的第一个正式版本。但愿愈来愈多的人可以参与进来,和咱们一块儿把 Element 作得更好。
- [https://github.com/babel/babel](https://github.com/babel/babel)
- [https://github.com/lerna/lerna](https://github.com/lerna/lerna)
- [https://github.com/ElemeFE/postcss-salad](https://github.com/ElemeFE/postcss-salad)
- [https://github.com/QingWei-Li/vue-markdown-loader](https://github.com/QingWei-Li/vue-markdown-loader)
- https://github.com/ElemeFE/cooking
问题1:官网是多少?
问题1:官网是element.eleme.io
问题2:如何修改样式?
回答2:简单的样式能够经过覆盖来修改;对于大规模的自定义,咱们提供了一套自定义主题的工具,文档看这里:https://github.com/ElemeFE/element/blob/master/custom-theme.md 。简单来讲,经过修改样式变量、编译主题、引入主题,就能够实现自定义主题。
问题3:Vue的做者给出了一套学习Vue路径,那Element是否有阅读源码的路径呢,怎么样才能够较为方便的理解源码,而且在基础组件不能知足本身业务的时候写出本身的组件呢?
回答3:阅读源码的话,能够先 clone 项目后,先试试用 npm run new 指令建立一个新组件,看看咱们的一个组件包含了哪些东西。要理解源码的话就本身边改代码边测试效果吧。
问题4:怎么看待vue添加redux,而又保留双向绑定的数据方式?
问题 4:不太明白想问什么。
问题5:国际化网站怎么作的,是每种语言对应一个页面吗,仍是统一的一个页面
回答5:Element 的主页是一个 SPA,每种语言对应了一个 .vue 文件,而这些 .vue 文件是经过一个统一的模板和语言配置文件生成出来的。
问题6:分享图中有一个文件夹 Loacel,是不是 locale 的笔误?
回答6:抱歉,咱们的失误,图中确实应该是 locale。
问题7:请问会推出专门针对移动端的Vue2组件库吗?
回答7:回答7:目前没有将 Element 移植到移动端的计划。不过,咱们已经有一套移动端组件库了:https://github.com/ElemeFE/mint-ui ,它有两个版本,分别兼容 Vue 1.x 和 2.0。
问题8:写在 vue 文件中的 markdown 输出在哪里?这并非现实效果的一部分呀?
回答8:Vue 和 Markdown 的结合,咱们是本身作了一个 vue-markdown-loader, 做用是将 Markdown 文件转成 Vue 组件(生成的文件在插件的 .cache 目录里),最后经过 vue-loader 处理。能够去看看这个 loader 的源码就明白了。
问题9:既然是基于vue了,那么element还有继续的必要吗?并且目前框架那么多,vue也获得了人的承认。element之后得生态如何保证?毕竟还只有目前饿了么一个团队在用。
回答9: 不太清楚“element还有继续的必要”是什么意思,据咱们在gitter对用户的了解,如今已经有很多用户将 element 实用到她们公司的产品开发里。element 的生态发展除了咱们团队自己之外还须要依靠开源的力量来进行优化和发展。
问题10:在组件开发中,有对复用性很高的业务组件作过积累吗?若是作过~是怎么维护这些业务组件的?也是同逻辑组件的维护方法同样吗?
回答10: 组件开发中会不断收到各类的功能需求的反馈,经过github仓库issue来推进咱们组件的功能更新和维护。不太清楚“逻辑组件”的含义,element 里除了按钮这样特殊的组件外都是带有逻辑的。
问题11:请问将常见的jq插件或者说jq动效写成vue组件的过程当中有什么不畅的地方吗?
回答11: 在组件开发过程当中没有参考任何jq插件的动效。实际上基于mvvm框架下的组件库开发相对于jq是轻松不少的,由于你不须要手动地处理事件绑定和视图的更新。
问题12:分享的文档是否有些陈旧没有更新,vue 目前已经不是 rc 阶段了
回答12:文档中说「开发时」Vue 还处于 RC 阶段,主要指的是今年的八九月份,那时 Vue 每更新一个 RC 版本,咱们就跟着作一遍测试,而后发现几个 bug 的情景还历历在目。Vue 2.0 是上个月正式发布的,咱们也在今天发布了 Element 的正式版。
问题13:有没有模板能够参考?
回答13:有,看这里:https://github.com/ElementUI/element-starter。若是熟悉 cooking 或 laravel,咱们也提供了相应的模板:https://github.com/ElementUI/element-cooking-starter 、 https://github.com/ElementUI/element-in-laravel-starter 。
问题14:element的开发者都是饿了么前端团队的吗,团队外的开发者占多少?
回答14:是的。不过自从 Element 开源以来,社区出现了一批热心用户,他们也贡献了本身的代码。全部贡献者能够从这里看到:https://github.com/ElemeFE/element/graphs/contributors 。
问题15:几年前,不计算Gzip 90kb的jQuery遭到了人们的嫌弃:太大了,仍是用原生吧。 几年后,开启Gzip后 仍有300kb的基于React的项目,人们以为:区区300kb而已,算很小了。巨型库的概念流行后,人们彷佛忘了啪啪啪在脸上有多疼。
你怎么看?
回答15:这几年网速已经提高很多,同时前端项目的复杂度也变得愈来愈高。比起库的体积,可能如今开发效率才是开发者所关心的。
问题16:Element这套组件和Ant Design感受有点相似,是否有借鉴过他们的设计?
回答16:有借鉴过,咱们不只借鉴过 AntDesign,国内外大大小小的 Design Language 都有借鉴学习。不少信息前人已经总结过,咱们但愿能够快速的得到这些知识,以便更快的走到前方去探索更前沿的设计。
问题17:感谢分享。目前有没有优秀应用案例能够分享?
回答17:目前咱们尚未精力去收集整理使用了 Element 的项目,不过按照最近一段时间在 Gitter 里讨论看到了一些开发者分享的项目连接,完成质量仍是挺高的。过段时间咱们会在 issue 里开始征集你们使用 Element 组件库的做品连接作分享。
问题18:如何定制css,是覆盖仍是改源码?改了源码若是element版本更新以后 样式就没了?
回答18:能够用 element-theme 主题自定义工具,或者直接下载 element-theme-default 主题包本身修改主题。若是只是简单的修改,建议直接覆盖样式。
问题19:您好,我是个初学者,看不大懂编程,初学要作前端,应该先从哪开始入手学习
回答19:回答19:freecodecamp 和 codecademy 都是很好的入门途径。
问题20:在技术选型的时候,基于什么考虑,选择了Vue,而不是React
回答20:由于和 react相比,咱们公司前端使用 Vue 的更多。为了照顾到大多数人,咱们选用 Vue 做为 Element 的框架。
问题21:我在写 vue 的组件通讯中,也发现事件比较好用但不容易被控制,所以通常是给自定义事件加上命名空间,如 $dispatch('AComponent::rotate', 90),Element 团队有这样的实践吗?
回答21:在 element 的组件中对组件通讯这一块并无用到全局的 event bug,而是经过dispatch和broadcast来进行相互依赖的组件间的通讯。虽然vue2.0里弃用了$dispatch和$broadcast的api,但咱们本身在组件库中封装了一遍。
问题22:Element 团队使用 Vuex 时的一些具体情景是什么?
回答22:22. element 没有用到vuex的情景
问题23:后续是否会开放一些常见业务组件,好比城市选择等
回答23:与后台业务关联很大的组件应该不会直接开放,不过这个组件若是能解决相似的其余问题,咱们会抽离业务属性将之做为「基础组件」开放出来。城市选择只用了比较基础的 Select 组合而已。
问题24:element 在作动画效果这个方向上有些什么成绩呢回答24:动画效果方面咱们尚未人力去探索和研究,主要精力仍是放在业务系统的搭建上