网站首页 > 技术文章 正文
require 实战
下面我将化整为零的去讲解requireJS在一个项目的具体使用方式以及需要注意的事项。
引入requireJS
通过 <script> 标签,将require.js 文件引入到当前的 HTML 页面中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>RequireJS 实战</title>
</head>
<body>
<script src="js/require.js"></script>
</body>
</html>
参数配置
requireJS 常用的方法与命令也就两个, 因此requireJS使用起来非常简单。
require
define
其中define是用于定义模块, 而require是用于载入模块以及载入配置文件。
在requireJS中一个文件就是一个模块, 并且文件名就是该模块的ID, 其表现则是以key/value的键值对格式, key即模块的名称(模块ID), 而value则是文件(模块)的地址,
因此多个模块便有多个键值对值, 这些键值对再加上一些常用的参数, 便是require的配置参数, 这些配置参数我们通常会单独保存在一个JS文件中, 方便以后修改、调用, 所以这个文件我们也称之为"配置文件"。
下面是requireJS的基本参数配置:
//index.html
<script>
require.config({
baseUrl:'js/',
paths:{
'jquery':'http://xxxx.xxx.com/js/jquery.min',
'index':'index'
}
});
require(['index']);
</script>
require.config() 是用于配置参数的核心方法, 它接收一个有固定格式与属性的对象作为参数, 这个对象便是我们的配置对象。
在配置对象中 baseUrl 定义了基准目录, 它会与 paths中模块的地址自动进行拼接, 构成该模块的实际地址, 并且当配置参数是通过script标签嵌入到html文件中时, baseUrl默认的指向路径就是该html文件所处的地址。
paths 属性的值也是一个对象, 该对象保存的就是模块key/value值。其中key便是模块的名称与ID, 一般使用文件名来命名, 而value则是模块的地址, 在requireJS中, 当模块是一个JS文件时,
是可以省略 .js 的扩展名, 比如 "index.js" 就可以直接写成 "index" 而当定义的模块不需要与 baseUrl 的值进行拼接时, 可以通过 "/" 与 http:// 以及 .js 的形式来绕过 baseUrl的设定。
示例:
require.config({
baseUrl:'js/',
paths:{
'jquery':'http://xxx.xxxx.com/js/jquery.min',
'index':'index'
}
});
require(['index']);
实际上, 除了可以在require.js加载完毕后, 通过require.config()方法去配置参数, 我们也可以在require.js加载之前, 定义一个全局的对象变量 require 来事先定义配置参数。
然后在require.js被浏览器加载完毕后, 便会自动继承之前配置的参数。
<script>
var require = {
baseUrl: 'js/',
paths: {
'jquery': 'http://xxx.xxxx.com/js/jquery.min',
'index': 'index'
},
deps:[index]
};
</script>
<script src="js/require.js"></script>
不论是在require.js加载之前定义配置参数, 还是之后来定义, 这都是看看我们需求而言的, 这里我们举例的配置参数都是放入到script标签中, 然后嵌入到HTML页面的内嵌方式,
在实际使用时, 我们更多的则是将该段配置提取出来单独保存在一个文件中, 并将其取名为 app.js, 而这个 app.js 便是我们后面常说到的配置文件。
另外还有一个"接口文件"的概念, requireJS中, 所谓接口文件指的便是require.js加载完毕后第一个加载的模块文件。
加载配置文件
现在我们知道require的配置有两种加载方式,一种是放入到script标签嵌入到html文件中,另一种则是作为配置文件 app.js 来独立的引入。
独立的引入配置文件也有两种方式,一种是通过script标签加载外部JS文件形式:
<script src="js/require.js"></script>
<script src="js/app.js"></script>
另一种方式则是使用 require 提供的 data-main 属性, 该属性是直接写在引入require.js的script标签上, 在require.js 加载完毕时, 会自动去加载配置文件 app.js。
<script data-main="js/app" src="js/require.js"></script>
通过 data-main 去加载入口文件, 便会使配置对象中的 baseUrl 属性默认指向地址改为 app.js 所在的位置, 相比之下我更加推荐这种方式, 因为它更可能的方便快捷。
当我们的项目足够的庞大时, 我也会推荐将入口文件作为一个普通的模块, 然后在这个模块中, 根据业务的不同再去加载不同的配置文件。
//define.js
define(['app1','app2','app3','app4'],function(app1,app2,app3,app4){
if(page == 'app1'){
require.config(app1);
}else if(page == 'app2'){
require.config(app2);
}else if(page == 'app3'){
require.config(app3);
}else{
require.config(app4);
}
})
定义模块
在我们选择requireJS来模块化开发我们的项目或者页面时, 就要明确的知道我们以后所编写的代码或者是某段功能, 都是要放在一个个定义好的模块中。
下面是requireJS定义模块的方法格式:
define([id,deps,] callback);
ID:模块的ID, 默认的便是文件名, 一般无需使用者自己手动指定。
deps:当前模块所以依赖的模块数组, 数组的每个数组元素便是模块名或者叫模块ID。
callback:模块的回调方法, 用于保存模块具体的功能与代码, 而这个回调函数又接收一个或者多个参数, 这些参数会与模块数组的每个数组元素一一对应, 即每个参数保存的是对应模块返回值。
根据 define() 使用时参数数量的不同, 可以定义以下几种模块类型:
简单的值对
当所要定义的模块没有任何依赖也不具有任何的功能, 只是单纯的返回一组键值对形式的数据时, 便可以直接将要返回的数据对象写在 define方法中:
define({
'color':'red',
'size':'13px',
'width':'100px'
});
这种只为保存数据的模块,我们称之为“值对”模块,实际上值对模块不仅可以用于保存数据,还可以保存我们的配置参数,然后在不同的业务场景下去加载不同的配置参数文件。
示例:
//app1.js
define({
baseUrl:'music/js/',
paths:{
msuic:'music',
play:'play'
}
});
//app2.js
define({
baseUrl:'video/js/',
paths:{
video:'video',
play:'play'
}
});
非依赖的函数式定义
如果一个模块没有任何的依赖, 只是单纯的执行一些操作, 那么便可以直接将函数写在 define方法中:
define(function(require,exports,modules){
// do something
return {
'color':'red',
'size':'13px'
}
});
依赖的函数式定义
这种带有依赖的函数式模块定义, 也是我们平时常用到的, 这里我们就结合实例, 通过上面所举的 index 模块为例:
//index.js
define(['jquery','./utils'], function($) {
$(function() {
alert($);
});
});
从上面的示例中我们可以看出 index 模块中, 依赖了 'jquery' 模块, 并且在模块的回调函数中, 通过 $ 形参来接收 jquery模块返回的值, 除了 jquery 模块, index模块还依赖了 utils 模块,
因为该模块没有在配置文件中定义, 所以这里以附加路径的形式单独引入进来的。
载入模块
在说载入模块之前, 我们先聊聊"模块依赖"。模块与模块之间存在着相互依赖的关系, 因此就决定了不同的加载顺序, 比如模块A中使用到的一个函数是定义在模块B中的,
我们就可以说模块A依赖模块B, 同时也说明了在载入模块时, 其顺序也是先模块A, 再模块B。
在require中, 我们可以通过 require() 方法去载入模块。其使用格式如下:
require(deps[,callback]);
deps:所要载入的模块数组。
callback:模块载入后执行的回调方法。
这里就让我们依然使用上述的 index 模块为例来说明
示例:
require.config({
paths:{
'index':'index'
}
});
require(['index']);
requireJS 通过 require([]) 方法去载入模块, 并执行模块中的回调函数, 其值是一个数组, 数组中的元素便是要载入的模块名称也就是模块ID,
这里我们通过 require(['index']) 方法载入了 index 这个模块, 又因为该模块依赖了 jquery 模块, 所以接着便会继续载入jquery模块, 当jquery模块加载完成后,
便会将自身的方法传递给形参 $ 最后执行模块的回调方法, alert出$参数具体内容。
这里我们可以小小的总结一下,实现模块的载入除了 require([],fn) 的主动载入方法,通过依赖也可以间接载入对应的模块,但是相比较而言require方式载入模块在使用上更加灵活,它不仅可以只载入模块不执行回调,也可以载入模块然后执行回调,还可以在所定义的模块中,按需载入所需要用到的模块,并且将模块返回的对象或方法中保存在一个变量中,以供使用。
这种按需载入模块, 也叫就近依赖模式, 它的使用要遵循一定的使用场景:
当模块是非依赖的函数式时,可以直接使用
define(function(require,exports,modules){
var utils = require('utils');
utils.sayHellow('hellow World')
})
当模块是具有依赖的函数式时, 只能够以回调的形式处理。
define(['jquery'], function($) {
$(function() {
require(['utils'],function(utils){
utils.sayHellow('Hellow World!');
});
});
});
当然聪明伶俐的你, 一定会想到这样更好的办法:
define(['jquery','require','exports','modules'], function($,require,exports,modules) {
$(function() {
//方式一
require(['utils'],function(utils){
utils.sayHellow('Hellow World!');
});
//方式二:
var utils = require('utils');
utils.sayHellow('hellow World')
});
});
模块的返回值
require中定义的模块不仅可以返回一个对象作为结果,还可以返回一个函数作为结果。实现模块的返回值主要有两种方法:
return 方式
// utils.js
define(function(require,exports,modules){
function sayHellow(params){
alert(params);
}
return sayHellow
});
// index.js
define(function(require,exports,modules){
var sayHellow = require('utils');
sayHellow('hellow World');
})
如果通过return 返回多种结果的情况下:
// utils.js
define(function(require,exports,modules){
function sayHellow(params){
alert(params);
}
function sayBye(){
alert('bye-bye!');
}
return {
'sayHellow':sayHellow,
'sayBye':sayBye
}
});
// index.js
define(function(require,exports,modules){
var utils = require('utils');
utils.sayHellow('hellow World');
})
exports导出
// utils.js
define(function(require,exports,modules){
function sayHellow(params){
alert(params);
}
exports.sayHellow = sayHellow;
})
// index.js
define(function(require,exports,modules){
var utils = require('utils');
utils.sayHellow('hellow World');
});
这里有一个注意的地方, 那就是非依赖性的模块, 可以直接在模块的回调函数中, 加入以下三个参数:
require:加载模块时使用。
exports:导出模块的返回值。
modules:定义模块的相关信息以及参数。
非标准模块定义
在 require.config() 方法的配置对象中有一个 shim 属性, 它的值是一个对象, 可以用于声明非标准模块的依赖和返回值。
所谓的 "非标准模块" 指的是那些不符合的AMD规范的JS插件。
下面我们先看看基本的 shim 配置参数:
require.config({
baseUrl:'js/',
paths:{
'jquery':'http://xxx.xxxx.com/js/jquery.min',
'index':'index',
'say':'say',
'bar':'bar',
'tools':'tools'
},
shim:{
'tools':{
deps:['bar'],
exports:'tool'
},
'say':{
deps:['./a','./b'],
init:function(){
return {
'sayBye':sayBye,
'sayHellow':sayHellow
}
}
}
}
});
require(['index']);
这里需要注意的是如果所加载的模块文件是符合AMD规范, 比如通过 define 进行定义的, 那么require默认的优先级将是标准的, 只有在不符合标准的情况下才会采用shim中定义的参数。
在 index 模块执行时:
define(['jquery','tool','say'],function($,tool,say){
tool.drag();
say.sayHellow();
say.sayBye();
})
上面的示例中, 关于 shim 中有三个重要的属性, 它们分别是:
deps: 用于声明当前非标准模块所依赖的其它模块, 值是一个数组, 数组元素是模块的名称或者是ID。
exports:用于定义非标准模块的全局变量或者方法。值一般是一个字符串。
init:用于初始, 处理, 非标准模块的全局变量或者是方法, 常用于当非标准模块存在多个全局变量以及方法, 值是一个函数。
常用参数
在 require.config 中还存在其他的常用属性设置。
urlArgs
RequireJS获取资源时附加在URL后面的额外的query参数。作为浏览器或服务器未正确配置时的“cache bust”手段很有用。使用cache bust配置的一个示例:
javascript:;urlArgs: "bust=" + (new Date()).getTime()
在开发中这很有用,但请记得在部署到生成环境之前移除它。
scriptType
指定RequireJS将script标签插入document时所用的type=""值。默认为“text/javascript”。想要启用Firefox的JavaScript 1.8特性,可使用值“text/javascript;version=1.8”。
waitSeconds
通过该参数可以设置requireJS在加载脚本时的超时时间,它的默认值是7,即如果一个脚本文件加载时长超过7秒钟,便会放弃等待该脚本文件,从而报出timeout超时的错误信息,考虑到国内网络环境不稳定的因素,所以这里我建议设置为0。当然一般不需要去改动它,除非到了你需要的时候。
deps
用于声明require.js在加载完成时便会自动加载的模块, 值是一个数组, 数组元素便是模块名。
callback
当deps中的自动加载模块加载完毕时,触发的回调函数。
config
config属性可以为模块配置额外的参数设定,其使用格式就是以模块名或者模块ID为key,然后具体的参数为value。
//app.js
require.config({
baseUrl:'js/',
paths:{
'jquery':'http://xx.xxxx.com/js/jquery.min',
'index':'index'
},
config:{
'index':{
'size':13,
'color':'red'
}
}
});
//index.js
define(['jquery','module'],function($,module){
console.log(module.config().size)
});
这里要引起我们注意的地方就是依赖的'module'模块, 它是一个预先定义好的值, 引入该值, 在当前模块下便可以调用module对象, 从该对象中执行 config() 方法便可以生成改模块的参数对象。
实战:
<script data-main="js/app.js" src="js/require.js"></script>
app.js为入口函数, 其代码为:
requirejs.config({
//默认情况下模块所在目录为js/lib
baseUrl: 'js/lib',
//当模块id前缀为app时,他便由js/app加载模块文件
//这里设置的路径是相对与baseUrl的,不要包含.js
paths: {
app: '../app'
}
});
// 开始逻辑.
requirejs(['jquery', 'canvas', 'app/sub'],
function ($, canvas, sub) {
//jQuery, canvas and the app/sub module are all
//loaded and can be used here now.
});
实战2:
文件功能
require.js:
其中requirejs的核心代码就是require.js文件,可以从官方网站上下载:
config.js:
用于配置requirejs的相关内容,可以设置文件目录,加载模块命名匹配,以及一些依赖关系等等。
index.html:
我们的测试页面或者网址首页。
/lib/a.js和/lib/b.js 以及 /others/c.js
是测试的模块js文件。
index.html
<doctype html>
<html>
<meta http-quiv="Content-Type" content="text/html;charset=UTF-8">
<script data-main="config" src="require.js"></script>
</html>
<body>
<h1>This is test for RequireJS</h1>
<script type="text/javascript">
alert("index");
</script>
</body>
其中, data-main指定主要的配置文件, src为requirejs的文件。
config.js
require.config({
baseUrl:'/', /* 项目必须放到根目录下才能正确执行 */
paths:{
"a":"lib/a",
"b":"lib/b",
"c":"others/c"
}
});
require(['a','b','c'],function(a,b,c){
a.hello();
b.hello();
c.hello();
});
baseUrl指定所有文件的主要目录, paths配置模块名字以及其匹配的加载路径。
当有需要使用某些模块时, 就可以通过require([xxx],function(xxx){xxx});的方式使用。
a.js
define([], function() {
return {
hello: function() {
alert("hello, a");
}
}
});
b.js
define([], function() {
return {
hello: function() {
alert("hello, b");
}
}
});
c.js
define([], function() {
return {
hello: function() {
alert("hello, c");
}
}
});
模块化文件, 一般是一个功能是一个文件。文件的名字, 就是上面requireconfig中配置的模块名字。require加载文件时, 会自动加上.js后缀。
当某些模块依赖其他模块时, 可以通过define([xxx],function(xxx){yyy});的方式添加依赖关系, require会在异步加载后, 自动调整次序。
当访问index.html时, 会先加载require.js然后把需要加载的文件都通过appendChild的方式, 添加到index.html的底部。
因此会先弹出index对话框, 当执行config.js的后半部分代码时, 会依次使用a.js b.js c.js, 因此也会依次弹出三个对话框。
猜你喜欢
- 2024-10-24 Service Workers - JS API 简介(servicedescriptor)
- 2024-10-24 web性能优化的15条实用技巧(web应用性能优化思路)
- 2024-10-24 如何在 Service Worker 重新启动时重用信息
- 2024-10-24 Python在selenium里面注入JavaScript程序的方法
- 2024-10-24 面试妥了!2020 爬虫面试题目合集(爬虫面试经历)
- 2024-10-24 Nest.js 从零到壹系列(一):项目创建&路由设置&模块
- 2024-10-24 JS小知识,分享 7 个高频的工具函数,也许你用的上
- 2024-10-24 如何使用Playwright优化测试性能(play—player)
- 2024-10-24 JavaScript开发人员都应知道的异步迭代,你会了吗?
- 2024-10-24 WebSocket能干些啥?(websocket作用)
- 11-26Win7\8\10下一条cmd命令可查得笔记本电脑连接过的Wifi密码
- 11-26一文搞懂MySQL行锁、表锁、间隙锁详解
- 11-26电脑的wifi密码忘记了?一招教你如何找回密码,简单明了,快收藏
- 11-26代码解决忘记密码问题 教你用CMD命令查看所有连接过的WIFI密码
- 11-26CMD命令提示符能干嘛?这些功能你都知道吗?
- 11-26性能测试之慢sql分析
- 11-26论渗透信息收集的重要性
- 11-26如何查看电脑连接过的所有WiFi密码
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)