yuanyuangugu 2019-07-01
在cmd
命令窗口通过npm install saejs
下载
seajs
的npm
下载指令查找方法如下
下载完成后,生成一个node_modules
目录,seajs
核心文件放在node_modules\seajs\dist
下,如下图所示
seajs
新建index.html
文件,将sea.js
和index.html
放在同一级目录
在index.html
中通过script
标签引入sea.js
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <!-- 引入sea.js --> <script type="text/javascript" src="./sea.js"></script> <script type="text/javascript"> console.log(seajs) </script> </body> </html>
seajs
向外暴露了一个变量seajs
,在上面代码中输出seajs
从控制台的输出可以看到,seajs是一个对象,有很多属性
和方法
,我们对其的配置,就是调用了里面的config()
方法
config
方法的源码
seajs.config = function(configData) { for (var key in configData) { var curr = configData[key] var prev = data[key] // Merge object config such as alias, vars if (prev && isObject(prev)) { for (var k in curr) { prev[k] = curr[k] } } else { // Concat array config such as map if (isArray(prev)) { curr = prev.concat(curr) } // Make sure that `data.base` is an absolute path else if (key === "base") { // Make sure end with "/" if (curr.slice(-1) !== "/") { curr += "/" } curr = addBase(curr) } // Set config data[key] = curr } } emit("config", configData) return seajs }
从config
方法的源码for (var key in configData)
可知,config()
方法的参数应该是一个对象,每一种配置项是一个属性(key:value,key是配置名称,value是配置结果),遍历config()
方法的参数,并将每种配置的名称和结果放在seajs.data(也是一个对象)
里面
seajs模块标识分为3种:相对标识、顶级标识和普通标识。
相对路径,以. 或 ..开头
顶级路径,不以.或 ..及斜线(/)开头
普通路径,除相对和顶级路径外的,比如/(根路径)开头的,"http://"、"https://"、"file:///" 等协议标识开头的
模块命名空间是seajs所在文件的根路径即所谓的base路径,去除了seajs/x.y.z 字串,也可以指定seajs.config({base:});
base
配置项在不设置时,表示的是sea.js
文件位置,因为seajs
的配置结果存放在seajs.data
中,在控制台输出seajs.data
本地电脑上sea.js
文件位置
证明base
就是sea.js
文件所在的路径
在main.js
中定义一个模块,并向外暴露
//main.js // 定义一个没有ID的模块 define(function(require,exports,module){ // 向外暴露 module.exports.name = '张三' })
在index.html
文件中使用seajs.use()
方法引入入口模块文件main.js
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <!-- 引入sea.js --> <script type="text/javascript" src="./sea.js"></script> <script type="text/javascript"> //引入入口模块 seajs.use('main',function(a){ console.log(a) //a为引入的入口文件内的模块向外暴露的对象 console.log('入口模块引入完毕') }) </script> </body> </html>
注意看seajs.use()
方法里面的第一个参数,"main"
乍一看好像没问题,mian.js
不就是和index.html
在同一级目录吗,其实不然,这是顶级路径
(不以.
、..
、/
开头,直接以文件名
或者文件夹名
开头),是相对于sea.js
的路径而言的,只是刚好这里sea.js
和index.html
在同一级目录,所以看起来像是相对于index.html
,如果写成./main
才是相对于index.html
的路径而言
那我们尝试更改一下sea.js
的位置,将sea.js
放在和index.html
同级目录的module
文件夹下(E:\SeajsTest\module\
),将main.js
放在和index.html
同级目录的module
文件夹下的main
文件夹中
因为sea.js
和main.js
的位置变了,此时sea.js
的路径是E:\SeajsTest\module\seajs
,引入sea.js
后在控制台输出seajs.data
验证
此时引入main.js
时,如果使用顶级路径
应该是main/main
,或者写相对路径
----./module/main/main
,表示相对于index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <!-- 引入sea.js --> <script type="text/javascript" src="./module/sea.js"></script> <script type="text/javascript"> //引入入口模块 // 1、使用顶级标识符 seajs.use('main/main',function(a){ // 2、使用相对标识符 // seajs.use('./module/main/main',function(a){ console.log(a) console.log('入口模块引入完毕') }) </script> </body> </html>
控制台输出
修改默认base
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <!-- 引入sea.js --> <script type="text/javascript" src="./module/sea.js"></script> <script type="text/javascript"> // 修改base seajs.config({ base:'main/' //base:"./main"写法是错误,因为也遵循seajs标识符的规则,./main/表示和index.html同级的main目录下 }) //引入入口模块 // 1、使用顶级标识符 seajs.use('main',function(a){ // 2、使用相对标识符 // seajs.use('./module/main/main',function(a){ console.log(a) console.log('入口模块引入完毕') }) </script> </body> </html>
如上所示,我将base
修改为main/
表示和sea.js
同级的main
目录下,即E:\SeajsTest\module\main
,此处不能使用base:./main/
,因为加上./
就表示相对于index.html
了,从下图中控制台输出的路径就可以看出来
当模块标识
很长,写起来不方便、容易出错的时候,可以使用alias来简化模块标识;还有一种情况当,我们引入一些基础库时,经常会涉及到版本升级(版本号发生改变),此时在每个模块中修改版本号比较麻烦,如果使用alias
定义这个模块,只需在seajs
的alias
中修改一次即可。在seajs.config中进行一次配置
之后,所有js模块
都可以用require("jquery")这种简单的方式来加载对应的模块了。使用alias,可以让文件的真实路径与模块调用标识分开
,有利于统一维文件目录如下
│ index.html │ main.js │ sea.js └─ module ├─Jquery │ Jquery1.12.4.js
我在index.html
中引入入口文件mian.js
,然后在main.js
中引入Jquery1.12.4.js
//index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <!-- 引入sea.js --> <script type="text/javascript" src="./sea.js"></script> <script type="text/javascript"> //引入入口文件 seajs.use('main',function(a){ console.log(a); console.log('入口文件加载完毕') }) </script> </body> </html>
//main.js // 定义一个没有ID的模块 define(function(require,exports,module){ //在入口模块中引入其他模块 var jq = require('module/Jquery/Jquery1.12.4') // 向外暴露 module.exports.name = '张三'; module.exports.JQ = jq; })
上面的写法是我们没有配置alias
时的写法,我现在觉得这个Jquery1.12.4.js
的标识符
太长,写起来太麻烦,此时就可以设置别名,注意这里的别名是针对某个文件(模块)
的标识符
,所以alias
的值要带上路径
(不是只给文件名设置别名)而且精确到文件,同样的,别名的设置也遵循seajs标识符规则
//index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <!-- 引入sea.js --> <script type="text/javascript" src="./sea.js"></script> <script type="text/javascript"> // 配置seajs seajs.config({ alias:{ //顶级标识符写法 'JQ':"module/Jquery/Jquery1.12.4", // 相对标识符写法 // 'JQ':"./module/Jquery/Jquery1.12.4" } }) //引入入口文件 seajs.use('main',function(a){ console.log(a); console.log('入口文件加载完毕') }) </script> </body> </html>
//main.js // 定义一个没有ID的模块 define(function(require,exports,module){ //在入口模块中引入其他模块 // 未配置alias时引入 // var jq = require('module/Jquery/Jquery1.12.4') //配置alias后引入 var jq = require('JQ') //上面的`JQ`是顶级标识符,等于base的值加上别名JQ代表的模块路径 // 向外暴露 module.exports.name = '张三'; module.exports.JQ = jq; })
这样一设置,写起来就简单多了,而且一次设置,所以地方都可以用
当目录层次比较深
,或者是跨目录调用模块
的时候,可以用path
简化模块标识的书写,path
与alias
不同的是,path
针对的是某个文件夹。paths 配置可以结合 alias 配置一起使用,让模块引用非常方便。文件目录如下
│ index.html │ main.js │ sea.js │ └─module └─one └─two └─three A.js B.js
还是老规矩,index.html
中引入入口模文件块main.js
,然后在main.js
中在引入A.js
和B.js
,index.html
内容还和上面一样,下面是main.js
的代码
//main.js // 定义一个没有ID的模块 define(function(require,exports,module){ //在入口模块中引入其他模块 var moduleA = require('module/one/two/three/A.js') var moduleB = require('module/one/two/three/B.js') module.exports.person = moduleA; module.exports.studemt = moduleB; })
可以看到A.js
和B.js
文件位置相对于sea.js
和index.html
很深,所以在main.js
中引入时路径很长,当要引入three
文件夹下更多模块文件时,写起来很麻烦,这个是时候paths
就派上用场了,其实跟alias
有点像,可以看做是给某个文件夹
设置了别名
// 定义一个没有ID的模块 define(function(require,exports,module){ //在入口模块中引入其他模块 // 1、不配置paths时的写法 // var moduleA = require('module/one/two/three/A.js') // var moduleB = require('module/one/two/three/B.js') //2、配置paths后的写法 var moduleA = require('three/A.js'); var moduleB = require('three/B.js'); module.exports.person = moduleA; module.exports.studemt = moduleB; })
要是需要引入的模块在同一文件夹下,而且藏得又深名字还长,那么就使用alias
和paths
配合使用,给文件设置alias(别名)
,给文件夹设置paths(路径)
目录如下
│ index.html │ main.js │ sea.js │ └─module └─language en.js zh-cn.js
//index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <!-- 引入seajs --> <script src="./sea.js"></script> <!-- 引入入口模块文件 --> <script> // 配置seajs seajs.config({ vars:{ cn:"zh-cn" } }) // 使用seajs.use()方法引入入口模块 seajs.use('main',function(a){ console.log('入口模块加载完毕') // 输出入口模块向外暴露的对象 console.log(a); }) </script> </body> </html>
//main.js // 定义入口模块 define(function(require,exports,module){ // 引入其他模块 // 未配置vars时的写法 // var language = require('module/language/zh-cn') // 配置vars后的写法 var language = require('module/language/{cn}') module.exports.language = language; })
vars
是一个对象,对象内有kv
键值对,k
是一个变量,用于代替v
,在引入模块文件时,可以使用{}
包裹k
的形式来代替v
,形如{K}
,有点像插值语法,官网说是动态加载,看了很多文章都是引用官网的例子,哎,我也不知道什么场景下使用,我感觉和alias
真的一样
map
用于对模块路径进行映射修改,可用于路径转换,在线调试等文件目录如下
index.html │ main.js │ sea.js │ └─module debug.js runtime.js
//index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> <!-- 引入seajs --> <script src="./sea.js"></script> <script> // 配置seajs seajs.config({ map:[ ['runtime.js','debug.js'] ] }) // 引入入口模块 seajs.use('main',function(a){ console.log('入口模块加载完毕') console.log(a) }) </script> </body> </html>
// 定义入口模块 define(function(require,exports,module){ // 引入其他模块 var M = require('module/runtime') module.exports.state = M; })
上面的例子模拟了类似测试时的场景,将模块路径进行了转换