在html中引入requirejs
在HTML中,添加这样的 标签:
通常使用requirejs的话,我们只需要导入requirejs即可,不需要显式导入其它的js库,因为这个工作会交给requirejs来做。
属性 是告诉requirejs:你下载完以后,马上去载入真正的入口文件。它一般用来对requirejs进行配置,并且载入真正的程序模块。
在config.js中配置requirejs
中通常用来做两件事:
配置requirejs 比如项目中用到哪些模块,文件路径是什么
载入程序主模块
requirejs.config({ baseUrl: '/public/js', paths: { app: 'app' }}); requirejs(['app'], function(app) { app.hello();});在 中,我们声明了一个名为 的模块,以及它对应的js文件地址。在最理想的情况下, 的内容,应该使用requirejs的方式来定义模块:
define([], function() { return { hello: function() { alert("hello, app~"); } }});这里的 是requirejs提供的函数。requirejs一共提供了两个全局变量:
requirejs/require: 用来配置requirejs及载入入口模块。如果其中一个命名被其它库使用了,我们可以用另一个
define: 定义一个模块
另外还可以把 当作依赖的模块,然后调用它的方法:
define(["require"], function(require) { var cssUrl = require.toUrl("./style.css");});依赖一个不使用requirejs方式的库
前面的代码是理想的情况,即依赖的js文件,里面用了 这样的方式来组织代码的。如果没用这种方式,会出现什么情况?
比如这个 :
function hello() { alert("hello, world~");}它就按最普通的方式定义了一个函数,我们能在requirejs里使用它吗?
先看下面不能正确工作的代码:
requirejs.config({ baseUrl: '/public/js', paths: { hello: 'hello' }}); requirejs(['hello'], function(hello) { hello();});这段代码会报错,提示:
Uncaught TypeError: undefined is not a function
原因是最后调用 的时候,这个 是个 . 这说明,虽然我们依赖了一个js库(它会被载入),但requirejs无法从中拿到代表它的对象注入进来供我们使用。
在这种情况下,我们要使用 ,将某个依赖中的某个全局变量暴露给requirejs,当作这个模块本身的引用。
requirejs.config({ baseUrl: '/public/js', paths: { hello: 'hello' }, shim: { hello: { exports: 'hello' } }}); requirejs(['hello'], function(hello) { hello();});再运行就正常了。
上面代码 中的 ,是我们在 中定义的 函数。当我们使用 的方式定义一个函数的时候,它就是全局可用的。如果我们选择了把它 给requirejs,那当我们的代码依赖于 模块的时候,就可以拿到这个 函数的引用了。
所以: 可以把某个非requirejs方式的代码中的某一个全局变量暴露出去,当作该模块以引用。
暴露多个变量:init
但如果我要同时暴露多个全局变量呢?比如, 的定义其实是这样的:
function hello() { alert("hello, world~");}function hello2() { alert("hello, world, again~");}它定义了两个函数,而我两个都想要。
这时就不能再用 了,必须换成 函数:
requirejs.config({ baseUrl: '/public/js', paths: { hello: 'hello' }, shim: { hello: { init: function() { return { hello: hello, hello2: hello2 } } } }}); requirejs(['hello'], function(hello) { hello.hello1(); hello.hello2();});当 与 同时存在的时候, 将被忽略。
无主的与有主的模块
我遇到了一个折腾我不少时间的问题:为什么我只能使用 来依赖jquery, 而不能用其它的名字?
比如下面这段代码:
requirejs.config({ baseUrl: '/public/js', paths: { myjquery: 'lib/jquery/jquery' }}); requirejs(['myjquery'], function(jq) { alert(jq);});它会提示我:
但我仅仅改个名字:
requirejs.config({ baseUrl: '/public/js', paths: { jquery: 'lib/jquery/jquery' }}); requirejs(['jquery'], function(jq) { alert(jq);});就一切正常了,能打印出 相应的对象了。
为什么?我始终没搞清楚问题在哪儿。
有主的模块
经常研究,发现原来在jquery中已经定义了:
define('jquery', [], function() { ... });它这里的 跟我们前面看到的 不同,在于它多了第一个参数 ,表示给当前这个模块起了名字 ,它已经是有主的了,只能属于 .
所以当我们使用另一个名字:
去引用这个库的时候,它会发现,在 里声明的模块名 与我自己使用的模块名 不能,便不会把它赋给 ,所以 的值是 。
所以我们在使用一个第三方的时候,一定要注意它是否声明了一个确定的模块名。
无主的模块
如果我们不指明模块名,就像这样:
define([...], function() { ...});那么它就是无主的模块。我们可以在 里,使用任意一个模块名来引用它。这样的话,就让我们的命名非常自由,大部分的模块就是无主的。
为什么有的有主,有的无主
可以看到,无主的模块使用起来非常自由,为什么某些库(jquery, underscore)要把自己声明为有主的呢?
按某些说法,这么做是出于性能的考虑。因为像 , 这样的基础库,经常被其它的库依赖。如果声明为无主的,那么其它的库很可能起不同的模块名,这样当我们使用它们时,就可能会多次载入jquery/underscore。
而把它们声明为有主的,那么所有的模块只能使用同一个名字引用它们,这样系统就只会载入它们一次。
挖墙角
对于有主的模块,我们还有一种方式可以挖墙角:不把它们当作满足requirejs规范的模块,而当作普通js库,然后在 中导出它们定义的全局变量。
requirejs.config({ baseUrl: '/public/js', paths: { myjquery: 'lib/jquery/jquery' }, shim: { myjquery: { exports: 'jQuery' } }}); requirejs(['myjquery'], function(jq) { alert(jq);});这样通过暴露 这个全局变量给 ,我们就能正常的使用它了。
不过我们完全没有必要这么挖墙角,因为对于我们来说,似乎没有任何好处。
如何完全不让jquery污染全局的$
在前面引用jquery的这几种方式中,我们虽然可以以模块的方式拿到jquery模块的引用,但是还是可以在任何地方使用全局变量 和 。有没有办法让jquery完全不污染这两个变量?
在init中调用noConflict (无效)
首先尝试一种最简单但是不工作的方式:
requirejs.config({ baseUrl: '/public/js', paths: { jquery: 'lib/jquery/jquery' }, shim: { jquery: { init: function() { return jQuery.noConflict(true); } } }}); requirejs(['jquery'], function(jq) { alert($);});这样是不工作的,还是会弹出来一个非 的值。其原因是,一旦requirejs为模块名 找到了属于它的模块,它就会忽略 中相应的内容。也就是说,下面这段代码完全没有执行:
jquery: { init: function() { return jQuery.noConflict(true); }}使用另一个名字
如果我们使用挖墙角的方式来使用jquery,如下:
requirejs.config({ baseUrl: '/public/js', paths: { myjquery: 'lib/jquery/jquery' }, shim: { myjquery: { init: function() { return jQuery.noConflict(true); } } }}); requirejs(['myjquery'], function(jq) { alert($);});这样的确有效,这时弹出来的就是一个 。但是这样做的问题是,如果我们引用的某个第三方库还是使用 来引用jquery,那么就会报“找不到模块”的错了。
我们要么得手动修改第三方模块的代码,要么再为它们提供一个 模块。但是使用后者的话,全局变量 可能又重新被污染了。
使用map
如果我们有办法能让在继续使用 这个模块名的同时,有机会调用 就好了。
我们可以再定义一个模块,仅仅为了执行这句代码:
jquery-private.js
define(['jquery'], function(jq) { return jQuery.noConflict(true);});然后在入口处先调用它:
requirejs.config({ baseUrl: '/public/js', paths: { jquery: 'lib/jquery/jquery', 'jquery-private': 'jquery-private' }}); requirejs(['jquery-private', 'jquery'], function() { alert($);});这样的确可行,但是还是会有问题: 我们必须小心的确保 永远是第一个被依赖,这样它才有机会尽早调用 清除全局变量 和 。这种保证只能靠人,非常不可靠。
我们这时可以引入 配置,一劳永逸地解决这样问题:
这样做,就解决了前面的问题:在除了jquery-private之外的任何依赖中,还可以直接使用 这个模块名,并且总是被替换为对 的依赖,使得它最先被执行。
- 1

究竟是什么挡住了攻击支付宝的黑客?
阅读量:2446
阅读全文
- 2

Redis漏洞以及可能导致的远程攻击分析
阅读量:2239
阅读全文
- 3

利用 :before :after 写小三角形
阅读量:2432
阅读全文
- 4
Vue问得最多的面试题
- 5
最新大厂web前端10道经典面试题(含答案详解)
- 6
吴翰清——一个曾在面试官前黑掉阿里系统的大佬
- 7
快速理解RequireJs中的config
- 8
创意卡片式项目管理界面UI设计源码
- 9
程序员加班很严重吗?看看国外同行如何怼回去
- 10
一些CSS使用的书写规范顺序与偏门又实用的 CSS 样式
扫码进入微信小程序版个人博客

- 527154335

- desiresss



