AMD规范

传统HTML文件的引入问题

一个HTML页面中,如果引用了多个js文件会发生什么样的事情?

比如我们下面的HTML文件中,引入了1.js和2.js,这两个文件中同时都设置了fun函数,那么此时执行哪一个?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script src="./1.js"></script>
    <script src="./2.js"></script>
    <script>
        console.log(fun())
    </script>
</body>
</html>

 

 

 此时的输出结果为2.js文件,那是因为2.js是在1.js后面引入的

第一种方法,使用IIFE来解决

//1.js
(function fun(){
    console.log("1.js文件")
})()
//2.js
(function fun(){
    console.log("2.js文件")
})()

但是此时会报错

 

 

 此时作用域隔离了,但是此时的全局变量也没了,如果想在html文件中执行fun函数怎么办?

将该变量或者函数设置为全局变量也就是给window对象设置属性

比如我们给1.js设置全局属性fun

(function () {
    window.fun=function fun(){
        console.log("1.js文件")
    }
  })()

 

 

 此时无论文件的引入顺序如何,结果都是输出1.js文件,因为只有一个全局的变量

但是IIFE隔离作用域也是有问题的,比如代码冗余的情况

比如1.js和2.js文件中,2.js想要引入1文件的函数(这个函数不是全局函数),不可以,必须自己单独再写一个,会造成代码冗余的情况

 AMD规范-require.js

AMD全称Asynchronous Module Definition(异步模块定义),代表库就是require.js

我们可以查看阮一峰老师的博客:http://www.ruanyifeng.com/blog/2012/11/require_js.html

require.js的下载地址:https://requirejs.org/docs/release/2.3.6/minified/require.js

直接复制代码,自己新建一个require.js

require.js的基本使用

 在index.html中引入

    <!-- data-main属性的作用是,指定网页程序的主模块。 -->
    <script src="./js/require.js" data-main="./js/main.js"></script>   

data-main属性的作用是,指定网页程序的主模块。
此时会输出

 

 

 

我们看一下如何进行进行暴露和引用的

我们在新建两个文件yuan.js和ju.js

yuan.js文件

define(function () {
    function mianji(r) {
      return Math.PI * r * r
    }
  
    return {
      mianji
    }
  })

ju.js文件

define(function () {
    function mianji(a,b) {
      return a * b
    }
  
    return {
      mianji
    }
  })
  

我们可以看到,yuan.js和ju.js用define()来包裹一个函数,我们称之为AMD的外壳,define是require.js封装的方法,返回的是一个对象,对象内部是暴露出去的内容

再来看main.js文件

require(['yuan', 'ju'], function (yuan, ju) {
    console.log(yuan.mianji(1))
    console.log(ju.mianji(1,2))
  })
  

main.js需要使用require方法来获取依赖文件,然后将依赖文件注入到回调函数当中,我们叫做“依赖注入”,通过这种方式来引入模块/文件

此时我们可以看到浏览器中输出:

 

 

 注意:

  • 依赖的名称是文件名,不需要加后缀名,并且需要加引号,注入的时候不需要加引号
  • 注入的名字可以不用依赖的名字,是按照引入顺序去进行注入的
require(['yuan', 'fang'], function (x, y) {
  console.log(x.mianji(1))
  console.log(y.mianji(1,2))
})

这两种引入的方法是等价的

别名的使用

我们看上面的代码的引入是没有路径的,那是因为我们是同目录引入,此时我们将yuan.js和ju.js的目录修位置,放到outer的文件夹内部

此时的依赖引入

require(['../outer/yuan', '../outer/ju'], function (yuan, ju) {
    console.log(yuan.mianji(1))
    console.log(ju.mianji(1,2))
  })

此时会发现引入是通过文件路径的,但是这样会影响代码的审查效率(美观性)和引入性

我们可以给路径设置别名

使用require对象的config方法类配置paths项

require.config({
    paths: {
      "yuan": "../outer/yuan",
      "ju": "../outer/ju"
    }
  })
  
require(['yuan', 'ju'], function (yuan, ju) {
    console.log(yuan.mianji(1))
    console.log(ju.mianji(1,2))
  })

 

 

 

设置暴露口

比如我们想要引入第三方库,这个库如果要引入并使用,必须要有AMD规范的标准暴露口,如果没有的话,引入进来不能使用

require.config({
    paths: {
      "yuan": "../outer/yuan",
      "ju": "../outer/ju",
      "jq": "./jquery",
    },
   
  })
  require(['yuan', 'ju', "jq"], function (x, y, $) {  
     $("#div").css("background-color","blue")
  })

 

 

报错的原因是因为jquery的这个版本是不符合AMD规范的,没有对define方法做适配

解决办法是加shim

require.config({
    paths: {
      "yuan": "../outer/yuan",
      "ju": "../outer/ju",
      "jq": "./jquery",
    },
    shim: {
      "jq": {
        exports: "$",
      },   
    }
  })
  require(['yuan', 'ju', "jq"], function (x, y, $) {  
     $("#div").css("background-color","blue")
  })

 

 shim是增加一个暴露口,目的是为了让不支持AMD规范的文件库,能够在AMD中运行

 如果有多个依赖项,可以在shim中继续配置

 

require.config({
    paths: {
      "yuan": "../outer/yuan",
      "ju": "../outer/ju",
      "jq": "./jquery",
      "jqu":"./jquery-ui"
    },
    shim: {
      "jq": {
        exports: "$",
      },  
    "jqu":{
        deps:["jq"]
    } 
    }
  })
  require(['yuan', 'ju', "jq","jqu"], function (x, y, $,jqu) {  
     $("#div").css("background-color","blue")
     $("#div").draggable()
  })

上面的代码表示jquery-ui本身要依赖jquery,所以我们要配置deps

注意:require.config()接受一个配置对象,这个对象除了有前面说过的paths属性之外,还有一个shim属性,专门用来配置不兼容的模块。具体来说,每个模块要定义;exports值(输出的变量名),表明这个模块外部调用时的名称;deps数组,表明该模块的依赖性。                                                                                                                                                                                                                                                  

posted @ 2021-10-26 17:17  keyeking  阅读(166)  评论(0编辑  收藏  举报