define({
data: 1,
func: function() {
return 'hello';
}
});
第三种方法对于定义纯JSON数据的模块非常合适。
模块的载入和引用
模块的寻址算法
上文说过一个模块对应一个js文件,而载入模块时一般都是提供一个字符串参数告诉载入函数需要的模块,所以就需要有一套从字符串标识到实际模块所在文件路径的解析算法。SeaJS支持如下标识:
绝对地址——给出js文件的绝对路径。
如:
复制代码 代码如下:
require("http://example/js/a");
就代表载入 。
相对地址——用相对调用载入函数所在js文件的相对地址寻找模块。
例如在 中载入
复制代码 代码如下:
require("./c");
则载入 。
基址地址——如果载入字符串标识既不是绝对路径也不是以”./”开头,则相对SeaJS全局配置中的“base”来寻址,这种方法稍后讨论。
注意上面在载入模块时都不用传递后缀名“.js”,SeaJS会自动添加“.js”。但是下面三种情况下不会添加:
载入css时,如:
复制代码 代码如下:
require("./module1-style.css");
路径中含有”?”时,如:
复制代码 代码如下:
require(<a href="https://example/js/a.json?cb=func">?cb=func</a>);
路径以”#”结尾时,如:
复制代码 代码如下:
require("http://example/js/a.json#");
根据应用场景的不同,SeaJS提供了三个载入模块的API,分别是seajs.use,require和require.async,下面分别介绍。
seajs.use
seajs.use主要用于载入入口模块。入口模块相当于C程序的main函数,同时也是整个模块依赖树的根。上面在TinyApp小例子中,init就是入口模块。seajs.use用法如下:
复制代码 代码如下:
//单一模式
seajs.use('./a');
//回调模式
seajs.use('./a', function(a) {
a.run();
});
//多模块模式
seajs.use(['./a', './b'], function(a, b) {
a.run();
b.run();
});
一般seajs.use只用在页面载入入口模块,SeaJS会顺着入口模块解析所有依赖模块并将它们加载。如果入口模块只有一个,也可以通过给引入sea.js的script标签加入”data-main”属性来省略seajs.use,例如,上面TinyApp的index.html也可以改为如下写法:
复制代码 代码如下:
<!DOCTYPE HTML>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>TinyApp</title>
</head>
<body>
<p></p>
<script src="https://www.jb51.net/article/sea.js" data-main="./init"></script>
</body>
</html>
这种写法会令html更加简洁。
require
require是SeaJS主要的模块加载方法,当在一个模块中需要用到其它模块时一般用require加载:
复制代码 代码如下:
var m = require('/path/to/module/file');
这里简要介绍一下SeaJS的自动加载机制。上文说过,使用SeaJS后html只要包含sea.js即可,那么其它js文件是如何加载进来的呢?SeaJS会首先下载入口模块,然后顺着入口模块使用正则表达式匹配代码中所有的require,再根据require中的文件路径标识下载相应的js文件,对下载来的js文件再迭代进行类似操作。整个过程类似图的遍历操作(因为可能存在交叉循环依赖所以整个依赖数据结构是一个图而不是树)。
明白了上面这一点,下面的规则就很好理解了:
传给require的路径标识必须是字符串字面量,不能是表达式,如下面使用require的方法是错误的:
复制代码 代码如下:
require('module' + '1');
require('Module'.toLowerCase());
这都会造成SeaJS无法进行正确的正则匹配以下载相应的js文件。
require.async
上文说过SeaJS会在html页面打开时通过静态分析一次性记载所有需要的js文件,如果想要某个js文件在用到时才下载,可以使用require.async:
复制代码 代码如下: