前言
一月份的时候,临近放假,拿到一个需求,新增一个产品,我一个前端对一个java后端,两个星期的开发时间。 因为大部分功能在别的产品都已经有了,基本都是简单处理一下拿过来,再添加一下额外需要的功能,比如选择出行国家等。前一天拿到文档看了下,搞清楚之后,第二天开工,基本一天就把功能做完了。这一天的大部分时间还是花在-找代码上。无他,实在是遗留的代码 不是很清晰。
因为系统比较旧,前后端也没有分离,jsp的,代码也很混乱,逻辑里面还有很多奇怪的注释,在这些上面做了很多无用功。 基本做好功能,联调测试,通过之后基本就OK了。
但是两个周的时间才用了两三天。还有十来天呢,怎么办呢,看着这些混乱的代码,本着造福别人,也为以后的方便,就想着,用模块重新组织一下吧。因为去年有过这方面经验,轻车熟路。所以,就有了后来的故事和今天的这篇文字。
改造前
改造前的代码大概是这个样子的:
特别约定
标准保费 元/人
优惠价 元/人
不多贴代码了,大概就是这个样子的。这种情况的原因大概是:
1.起初的页面是后端人员写的,没有很好的组织各种资源。写到一定数量之后,各种逻辑已经耦合在一起,别的人接手之后,又不敢乱改,就按以前的做法复制粘贴,做好自己的那一块。久而久之,页面就越来越复杂,冗余也越来越多,形成了一个恶性循环。
2.网络环境不允许。使用公司标配的联想笔记本,标装之后,收到公司安全策略的限制,很多技术网站无法访问,查资料有时候只能看百度快照,有些同事只好用手机或者自带电脑来解决这个问题。至于 github,google,基本是不可能的。
3.没有代码规范。基本每个人都是按照自己的风格来,最后归并之后的代码就显得很混乱。
由于不能使用脚手架自动化工具,这种情景要做模块化,requireJs/seaJs 是比较好的选择。去年用过requireJs,这次就用一下seaJs.
由于项目中的样式文件实在太多太杂,时间上不允许我重新组织一遍,所以就只对逻辑代码做了模块化处理。
组织模块
要组织模块,首先要弄清楚相应的规则。最好的方式当然是看 seajs文档 了.
这里也简单介绍下几个常用的功能。
// 页面中包括的js
再看一下配置信息:
seajs.config({
base:"./js/",
paths: { //当目录比较深,或需要跨目录调用模块时,可以使用 paths 来简化书写。
"seajs": "seajs/2.3.0/sea.js"
},
alias:{ // 设置别名,方便调用 , 当模块标识很长时,可以使用 alias 来简化。
"jquery" : "lib/jquery/1.10.0/jquery.min.js",
'Hello':'mod/mod4.js',
},
map: [
[".js",".js?1.0"]
],
debug:true //值为 true 时,加载器不会删除动态插入的 script 标签。插件也可以根据 debug 配置,来决策 log 等信息的输出。
});
然后是页面入口:
//main.js
/*
define define(factory)
define 接受 factory 参数,factory 可以是一个函数,也可以是一个对象或字符串。
factory 为对象、字符串时,表示模块的接口就是该对象、字符串。比如可以如下定义一个 JSON 数据模块:
define({ "foo": "bar" });
也可以通过字符串定义模板模块:
define('I am a template. My name is {{name}}.');
factory 为函数时,表示是模块的构造方法。执行该构造方法,可以得到模块向外提供的接口。factory 方法在执行时,默认会传入三个参数:require、exports 和 module:
define(function(require, exports, module) {
// 模块代码
});
*/
define(function (require, exports, module) {
var $ = require('jquery');
console.log($);
require('mod1');
var Hello = require('Hello');
Hello.init();
// other code...
});
看一下模块内的代码:
//mod1.js
define(function (require, exports, module) {
console.log('mod1加载完毕');
});
//mod4.js
define('Hello',function(require,exports, module) {
var Hello = {
sayHello:function(){
console.log('hello');
}
}
module.exports = Hello;
});
打开页面控制台,就会看到输出的信息:
说明我们的模块已经被成功的被加载了。
当然 实际的工作中还要用到各种插件,这就需要知道如何改造现有文件为 CMD 模块
这些在文档中都能找到。
以上简单介绍了使用seajs 组织模块的方法。
当然,模块写完之后呢,我们还需要相应的构建工具。
玉伯说:
如果使用 Sea.js,强烈推荐采用配套的构建工具来压缩、合并代码。如果不这么做,可能会带来不少额外的工作甚至隐患。
如果不合并代码,也能运行,你会看到你的插件代码都会以async的方式插入到页面的头部。而且需要你手动处理依赖关系,也产生了额外的请求,不是很友好。如下图:
所以,为了避免意外的发生,也为了减少请求数,应该合并模块。
我们来看一个实际的例子-支付宝的登陆页面。
在网页支付宝收银台中的运用
很直观的就能看到插模块的合并,这个合并的工作就是构建工具的功劳了。
我们也来实现一下。
先看效果吧,执行模块合并之后,入口文件可以是这样的:
这样就实现了模块的打包合并。
我这里使用了gulp来实现这一步, 代码如下:
//seajs合并模式
gulp.task("seajs", function () {
return merge(
gulp.src(src + '/js/!(lib)/**/*.js', {base: src + '/js'})
.pipe(transport())
.pipe(concat({
base: src + '/js'
}))
.pipe(replace({
patterns: replace_patterns
}))
.pipe(gulp.dest(dist + '/js')),
gulp.src([src + '/js/lib/**/*.js', src + '/js/common.js'], {
base: src + '/js'
})
.pipe(replace({
patterns: replace_patterns
}))
.pipe(gulp.dest(dist + '/js'))
);
});
使用gulp提取模块有其他更详细的教程,这里提供一个我认为比较好的:
介绍一种基于gulp对seajs的模块做合并压缩的方式
那个支付宝的登陆页 这里给出完整代码,给大家观摩:
支付宝快捷收银台
加载中...
登录支付宝
返回
改造后
改造到最后呢,页面逻辑清爽多了,再有新的模块,写好之后别人直接调用就可以了,write once, run everywhere .
define(function(require) {
var $ = require("jquery"),
$body = $(document.body),
setDate = require("components/setDate"),
selectCity = require("components/selectCity"),
commonTools = require("tools/commonTools"),
FastClick = require("fastClick"),
myLayer = require("myLayer");
//内部统计
var webTrends = require("webTrends");
webTrends.init();
// 百度统计
var baiduTrends = require("baiduTrends");
baiduTrends.init();
// 初始化时间选择
setDate.dateTime.init();
// 选择目的地
selectCity.init();
var actionList = {
'applyInsurance' :function(){
//xxx
}
});
完整的代码就不展示了,都是一些逻辑,没什么好看的。
最后
花了大概一个周的时间初步重构了一下项目代码,改得很粗糙,只是做了一些大概的拆分,毕竟遗留的代码太多,需要和小伙伴一起做这个事。
由于公司标装的电脑用不了npm那些,最后的一步是我在mac上弄好,然后拷贝到公司电脑上,中间还出了很多问题,不过好在能跑了,至于最后能不能用起来..只能说,努力吧。
seajs 可以说是上个年代的产物了,不过在一些老旧项目中,依然可以发挥光和热。
写到这里差不多也要结束了,我呢,也算完成了给自己定的一个小目标,不算多大的贡献,只当给自己一个交代。
以上大概就是全部内容,希望给大家带来一些启发和帮助,谢谢。