前言

前段时间在慕课网跟着视频做了一个简单的 2048 游戏,发现这个小项目非常适合用来实践 Seajs 模块化,现在就把我的实践过程和大家分享一下。

实践过程

准备

没有进行模块化之前总共有5个文件:

  • index.html 游戏页面
  • 2048.css 游戏样式文件
  • main.js 程序入口文件
  • showanimation.js 游戏动画文件
  • support.js 基础函数文件

main.js 需要使用 showanimation.jssupport.js 定义的函数。

showanimation.js 需要使用 support.js 定义的函数。

除了这些文件之外,这个项目还用了jQuery的库,用了百度的cdn

目前 js 文件引入顺序如下:

1
2
3
4
<script src="http://apps.bdimg.com/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="../static/game/support.js"></script>
<script src="../static/game/showanimation.js"></script>
<script src="../static/game/main.js"></script>

目录结构

2048文件目录结构

源文件可以在这里找到,有兴趣的朋友可以下载下来尝试一下。

引入Sea.js

Seajs官网下载Sea.js(本文用到的版本是 2.3.0)。在static目录下建立一个lib文件夹,存放下载下来的sea.js

然后引入:

1
<script src="../static/lib/sea.js"></script>

CMD规范改写

CMD ( Common Module Definition ) 是Seajs遵循的一种模块定义规范。规范当中,一个模块就是一个文件,因此我按照CMD规范改写 2048 游戏的3个 js 文件。

SeaJS 里,推崇的 Modules/Wrappings 规范是 CMD 规范:define(function(){ }) 直接是由开发者手写的,写完后,可直接不经过任何构建工具就在浏览器上加载运行。

1
2
3
4
define(function(require, exports, module) {
var a = require("a")
exports.foo = ...
});

首先,main.jsshowanimation.jssupport.js 三个文件都用 defined 函数包裹起来,define 接收一个匿名函数作为参数,该函数传入默认的三个参数 requireexportsmoudule

1
2
3
define(function(require, exports, moudule){
// support.js 代码
});
1
2
3
define(function(require, exports, moudule){
// showanimation.js 代码
});
1
2
3
define(function(require, exports, moudule){
// main.js 代码
});

接着,把 showanimation.jssupport.js 当中需要被其他模块调用的函数和变量使用 exports 暴露给其他模块。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 暴露变量
exports.documentWidth = documentWidth;
exports.gridContainerWidth = gridContainerWidth;
exports.cellSideLength = cellSideLength;
exports.cellSpace = cellSpace;

// 暴露函数
exports.getPostTop = function(i,j) {
// code
};

exports.getPostLeft = function(i,j) {
// code
};
......

然后,使用 require 来获取其他模块暴露的接口.

1
2
3
// main.js
var support = require('./support');
var animation = require('./showanimation');
1
2
// showanimation.js
var support = require('./support');

最后,将原来调用其它模块的方法或变量改写为,以下形式:

1
2
3
var a = require('./a');
// 调用模块 a 的方法
a.doSomething();
1
2
3
4
5
6
7
8
9
// main.js
// 调用变量
support.cellSpace = 20;
support.cellSideLength = 100;

// 调用 showanimation.js 方法
animation.showNumberWithAnimation(randx, randy, randNumber);
// 调用 support.js 方法
support.canMoveDown(board)

在页面当中加载入口模块

在引入 sea.js 之后,在该 script 标签之后,再写一段 seajs 的配置代码:

1
2
3
4
5
6
seajs.config({
base: "../static"
});

// 加载入口模块
seajs.use(["game/main"]);

运行

经过上述过程之后 2048 游戏已经完成了模块化,现在打开浏览器运行一下,就可以正确运行了。

2048运行效果

这里是完成后的代码。

使用Seajs的意义

使用 Seajs 将各个文件转变成一个个独立的模块,模块当中可以方便的对函数和变量进行命名,免去了多个文件之间命名冲突的烦恼。除此之外,使用 Seajs 还可以在 js 文件当中声明所需的依赖,不再需要手动在引入过程中管理,降低了开发时出错的几率。

在 EMCAScript6 import 功能出现之前,Seajs 的确是一个不错的前端模块化工具。

下一篇文章,我会谈一下如何用 spm3 进行Seajs标准构建。

感谢您的阅读,有不足之处请为我指出。

参考

  1. CMD 模块定义规范
  2. CommonJS 的 Modules/Transport 和 Modules/Wrappings 规范有什么区别? – 知乎
  3. 前端模块化开发的价值

本文地址 http://blog.acwong.org/2014/11/15/2048-with-seajs/