一. 规范
为了更好的性能, 建议 html 中没有内联的脚本, 只引用 requirejs 来加载脚本.
<script data-main="./main.js" src="./require.js"></script>
data-main 属性告诉 requirejs, 加载完 require.js 再去加载 main.js
二. 加载 js 文件
baseUrl: requirejs 相对于 baseUrl 来加载脚本
<script data-main="scripts/main.js" src="scripts/require.js"></script>
以上代码将 baseUrl 设置为 "scripts" 目录, 并且 main.js 会有一个 moduleID 为'main'
baseUrl 也能通过 RequireJS config 配置, 如果没有配置且没有使用 data-main 属性, 默认将使用包含当前 HTML 页面的目录路径作为 baseUrl
RequireJS 默认所有的依赖都是脚本, 因此可以省去后缀 .js , 当解析当该模块时, 路径会自动加上后缀.
当你想直接引用一个脚本, 而不是通过 "baseUrl + path" 的方式来寻找时, 只需要 module ID 有以下三个特征, requirejs 查找该模块时就不会加上 "baseUrl + path", 只会被当做相对于当前 HTML 的一个路径:
以 .js 结尾
以 / 开头
包含 http,https 协议
以下路径区分 app.js 以及 第三方库 library.js:
文件夹
- |-- index.html
- |-- js/
- |-- app/
- |-- sub.js
- |-- lib/
- |-- jquery.js
- |-- canvas.js
- |-- app.js
- |-- require.js
index.html
<script data-main="js/app.js" src="js/require.js"></script>
app.js
- require.config({
- // 默认从 js/lib 加载模块
- baseUrl: 'js/lib',
- // 以 app 开头的模块, 从 js/app 加载
- // paths 属性是相对 baseUrl 来说的: js/lib/../app = js/app
- paths: {
- app: '../app'
- }
- });
- // 实际的逻辑代码
- requirejs(['jquery', 'canvas', 'app/sub'],
- function ($, canvas, sub) {
- // 这些模块的 return 值, 依次被注入
- });
理想的情况是所有加载的模块都是通过 define() 定义的规范模块, 当加载非规范模块时, 需要使用shim 配置 (jquery3.1 已支持 define).
- js/lib/myLib.js
- function myFub(){
- console.log("i am not amd module");
- }
- js/app.js
- require.config({
- baseUrl: 'js/lib',
- paths:{
- app: '../app',
- },
- shim:{
- }
- })
- require(['jquery','myLib'],function(jquery,myLib){
- console.log(myLib); // undefined
- console.log(myFun); // function
- })
此时 myLib 为 undefined, 因为 myLib.js 不符合 AMD 规范, 但是打印 myFun 是有值的, 即全局范围内, myFun 是有定义的, 但是不能注入到 myLib 变量中.
此时通过配置 shim, 将变量注入到 myLib 中:
- shim:{
- 'myLib':{
- deps:[], // 声明依赖
- exports:'myFun' // myLib 中的某个全局变量, 将该变量暴露出去作为 myLib 的值
- }
- }
这样
- require(['jquery','myLib'],function(jquery,myLib){
- console.log(myLib); // myLib 被注入为 myFun 的值 function
- console.log(myFun); // function
- })
三. data-main 入口点
data-main 中设置的脚本是异步加载的:
- <script data-main="scripts/main" src="scripts/require.js"></script>
- <script src="scripts/other.js"></script>
- // main.js
- require.config({
- paths: {
- foo: 'libs/foo-1.1.3'
- }
- });
- // other.js
- require( ['foo'], function( foo ) {
- });
data-main 表明, 在 require.js 加载完之后去异步加载 main.js, 此时会继续执行 other.js, 这导致可能会先执行 other.js, 此时 require('foo') 实际上是去加载 (baseUrl: scripts/) scripts/foo.js, 而不是加载 scripts/libs/foo.js, 因为此时 main.js 可能还未执行.
四. 定义模块
模块定义了一个作用域来避免全局名称污染:
- // myLib.js
- define(function(){
- var a = {
- color:'black',
- size:"unsize"
- };
- return a;
- })
此时只能通过 require 加载 myLib.js, 全局下 window.a 为 undefined.
简单键值对, 如果一个模块没有任何依赖, 仅含值对.
- define({
- name:"conan",
- size:"small"
- })
函数式定义, 没有依赖, 但是需要做初始化工作.
- define(function(){
- // 初始化
- return {
- name:'conan',
- size:"small"
- }
- })
存在依赖, 第一个参数是依赖的名称数组, 第二个参数是函数, 其中参数为对应依赖返回的值.
- define(["./lib1", "./lib2"], function(lib1, lib2) {
- return {
- name: "conan",
- size: "small",
- addToCart: function() {
- lib1.decrement(this);
- lib2.add(this);
- }
- }
- }
- );
模块不一定返回对象, 任何函数的返回值都是允许的, 比如返回函数
- define(["./lib1", "./lib2"], function(lib1, lib2) {
- return function(title){
- console.log(title);
- }
- }
- );
命名模块
- define('foo/title',['my/lib1','my/lib2'], function(lib1, lib2){
- return {
- }
- })
当显式指定模块名称的时候, 使得模块更不具备移植性, 当把文件移到别的目录, 就得重命名. 因此最好避免对模块命名, 交给优化工具生成, 优化工具需要生产模块名将多个模块打包成一个包加快浏览器载入速度.
注意事项
如果需要在 define 内部使用类似 require('./relative/name') 加载一个相对路径的模块, 记得把 require 本身作为一个依赖注入, 同时相对路径的模块也是作为依赖:
- // myLib2.js
- define({
- name :"lib123"
- })
- // myLib.js
- define(['require','../app/myLib2'],function(require){
- var lib2 = require('../app/myLib2');
- console.log(lib2); // {name : "lib123"}
- var a = {
- name:'conan',
- size:"small"
- };
- return a;
- })
事实证明这样也行
- define(['../app/myLib2'],function(){
- var lib2 = require('../app/myLib2'); // 全局 require
- console.log(lib2); // {name : "lib123"}
- var a = {
- name:'conan',
- size:"small"
- };
- return a;
- })
- // 目录
- |-- index.html
- |-- js/
- |-- app/
- |-- sub.js
- |-- myLib2.js
- |-- lib/
- |-- jquery.js
- |-- myLib.js
- |-- app.js
- |-- require.js
生成相对于模块的 URL 地址: 当需要生成一个相对于该模块的 URL 地址时, 可以将 require 作为依赖注入??, 调用 require.toUrl()
- define(['require'],function(require){
- var lib2 = require.toUrl('../app/myLib2');
- console.log(lib2); // js/lib/../app/myLib2
- var a = {
- name:'conan',
- size:"small"
- };
- return a;
- })
同上, 不将 require 注入也行, 则使用全局的 require.
- define(function(){
- var lib2 = require.toUrl('../app/myLib2');
- console.log(lib2); // js/lib/../app/myLib2
- var a = {
- name:'conan',
- size:"small"
- };
- return a;
- })
五. 配置
map
如有两类模块需要使用不同版本的 foo 模块:
- requirejs.config({
- map: {
- 'some/newmodule': {
- 'foo': 'foo1.2'
- },
- 'some/oldmodule': {
- 'foo': 'foo1.0'
- }
- }
- });
- // 目录
- |-- foo1.0.js
- |-- foo1.2.js
- |-- some/
- |-- newmodule.js
- |-- oldmodule.js
当 some/newmodule 调用 require('foo') 时, 将获取 foo1.2.js
当 some/oldmodule 调用 require('foo') 时, 将获取 foo1.0.js
六. 插件 Dom Ready
某个模块需要操作 dom 时, 需要在 DOM 加载完成之后再执行模块.
- // 第一种方式: 回调
- require(['domReady'], function (domReady) {
- domReady(function () {
- //This function is called once the DOM is ready.
- //It will be safe to query the DOM and manipulate
- //DOM nodes in this function.
- });
- });
上诉代码也可以使用下面的 loader plugin 书写方式, 并建议采用下述方式.
第二种方式: loader plugin
- require(['domReady!'], function (doc) {
- // 在此操作 dom
- //document.
- });
注意: 如果 document 需要一段时间来加载 (也许是因为页面较大, 或加载了较大的 js 脚本阻塞了 DOM 计算), 使用 domReady 作为 loader plugin 可能会导致 RequireJS"超时" 错.
如果这是个问题, 则考虑增加 waitSeconds 配置项的值, 或在 require() 使用 domReady() 调用 (将其当做是一个模块).
七. 命名模块
前面一直在无视命名模块的概念, 直到遇到一个 bug.
- require.config({
- baseUrl: 'js/lib',
- paths:{
- app: '../app',
- jquery:'https://cdn.bootCSS.com/jquery/3.3.1/jquery' ---- 1
- }
- })
- require(['jquery'], function ($) { ---- 2
- console.log($); // 能打印出 jquery 对象
- })
而如果将 1,2 处的 jquery 改为 jquery1 或者其它字符串, 则会报错. 原因是因为 cdn 上的 jquery.js 本身有这么一段代码:
- if ( typeof define === "function" && define.amd ) {
- define( "jquery", [], function() {
- return jQuery;
- } );
- }
即该模块定义的是命名模块, 不能以其它名称去 require.
以下是一些命名模块的例子:
- // 目录
- js/
- |-- app/
- |-- lib/
- |-- lib.js
- |-- app.js
- |-- require.js
- // lib.js 该文件中定义了一个命名模块和一个匿名模块
- define([],function(){ // 匿名模块
- return {
- name:"noNameModule"
- }
- })
- define("namedModule",[],function(){ // 有名模块
- return {
- name:"namedModule"
- }
- })
- // app.js
- require.config({
- baseUrl: 'js/lib',
- paths:{
- app: '../app',
- }
- })
- require(['lib'],function(lib){ // 寻找 js/lib/lib.js, 找到匿名模块的输出
- console.log(lib); // noNameModule
- })
- require(['namedModule'], function (l) { // 寻找 js/lib/nameModule.js, 会报错
- console.log(l); // 前面寻找了 js/lib/lib.js 中有 nameModule 模块, 所以会输出 namedModule
- })
- // 情况一
- require.config({
- baseUrl: 'js/lib',
- paths:{
- app: '../app',
- }
- })
- require(['namedModule'], function (l) { // 寻找 js/lib/nameModule.js, 会报错
- console.log(l); // 没有输出
- })
- require(['lib'],function(lib){ // 寻找 js/lib/lib.js, 找到匿名模块的输出
- console.log(lib); // noNameModule
- })
- // 情况二
- require.config({
- baseUrl: 'js/lib',
- paths:{
- app: '../app',
- }
- })
- require(['lib'],function(lib){ // 寻找 js/lib/lib.js, 找到匿名模块的输出
- console.log(lib); // noNameModule
- require(['namedModule'], function (l) { // 寻找 js/lib/lib.js 里的 namedModule, 不会报错
- console.log(l); // namedModule
- })
- })
来源: http://www.bubuko.com/infodetail-2765483.html