问题的来源
先看一个实际的场景:
假如现在有这个已经做好的页面:
现在需要新做一个页面,页面中需要把上图的搜索框拿回来,包括css样式和js的智能提示功能都要保留。
这样的例子在开发时会经常出现,比如搜索框、好友列表、侧边栏。
现在很多开发人员为了方便,基本都是从原有的页面把相关的css,js直接抠出来,然后复制到新的页面。时间久了就会发现:代码很乱;每次都需要重新抠代码,很辛苦;如果是团队开发,经常会出现重复开发相似功能的事情。
所以,我们需要定义一个前端项目开发规范,减少复用代码的成本。
如何实现复用
其实,代码复用不是现在才提出来的,很早以前就有js框架实现一定程度的复用了,另外也有人开始使用一些 UI 库。但是这些都没解决根本问题:我们要复用的,不仅仅是一个弹窗,一个下拉菜单之类的基本效果,而是网页中形形色色的模块,这些模块不是事先可以做好的,而是根据业务需求不断添加的。
我们将任何可以重用的代码都称为组件。组件之间可以互相依赖。开发时可以直接使用现成的组件。更关键的,是网页中任何需要重用的模块都可以转化为组件。
那么,只要保证组件做起来,用起来都非常方便的话,那么实现复用将是非常容易的事。
注意,这里的组件不仅仅指弹窗等基础组件,比如整个侧边栏、顶部导航都可以做成组件。
如何加载组件
很多编程语言都内置了模块加载器,比如php有 include, java有 import 。但是 js没有,因此我们需要定义一个加载规范。这时,也许你会想到 CMD,AMD 等js模块加载技术。但这里我们还需要关心 css 的加载问题,而不仅仅局限在 js 上。
最原始的加载方式
使用 <script> 载入每个 js, 使用 <link> 载入每个 css 是最简单的加载方式,但这个方式有2个问题:
1. 无法处理组件依赖。
2. 网页请求多。
3. 几乎每个组件都有一个js和css,也就是引入一次,就要写2行代码,这是比较麻烦的。
将源文件合并后加载
这是针对最原始的加载方式的改进,也是比较靠谱的方案,它解决了模块依赖,请求多的问题。比如我们通常使用 jquery 就是将源码合并后加载的。但是,这要求开发者事先合并好组件源码,如果仅仅为了几个小组件就去合并一次,显然有点杀鸡用牛刀的感觉。
使用js动态加载
这是现在比较流行的另外一种动态加载方式,但是它看起来相对比较复杂。很多人也不愿意将项目变的更复杂。
各取精华,发挥优势
以上几个加载方式各有优劣,不能一味地使用同种加载方式,而是根据项目需要,分别使用不同的加载方式。
整个网站通用的代码(比如类似jquery的功能)应该使用合并后加载。而其它剩下的小组件,则使用 js动态加载。
具体案例
比如现在已经有一个现成的 Dialog 组件,那么任何网页都只需下面代码,即可加载组件:
use('Dialog', function(Dialog){
// 使用 Dialog
});
加载组件时,组件所对应的js和css都会加载过来,确保整个组件直接可用。
组件的源码可以放在三种位置:
项目的组件库里: dialog
相对当前文件: ./dialog
服务器: http://.../dialog
这意味着用户1可以做好dialog组件放到网上,用户2可以直接引用。
Dialog 组件的源码如下:
imports('Dialog.css'); // 加载组件js时,自动加载组件的css define(function(require){ var Dom = require('Dom'); // 组件的依赖项 /////// var Dialog = {}; /////// return Dialog; });
这里,也许有人会吐槽了,使用了 define , require 之类,会使代码变复杂。为什么不直接将js合并,并且使用 <script> 直接引入呢。
为了适应不同需求,组件也可以使用工具将其源码提取出来,比如上例的 Dialog 合并后, Dialog 将成为全局变量,而不是一个模块。
动态加载组件的性能问题
将组件动态加载,会导致一定的性能损耗,这里我们可以使用发布脚本的方式,将一些本来需要异步加载的组件源码直接合并过来。同时还可以做代码检查和压缩等事情。
总结
任何代码都可以做成组件,组件将根据需求不断积累。如果可以,还可以把组件共享出来,让更多人复用。这就是可迭代的组件化的前端开发方案。