现在有许多成熟的js模块加载器,比如requirejs和seajs等,但是对一些小的项目来说,它们的功能可能太过于“强大”,也许我们只是想要有一个能动态加载js的功能,或许我们只是想装B一下,让自己写出的页面没有一大堆的这样的东西。前面说的两种js加载器都是更强调模块性,也就是更强调js文件的组织和管理,更适用于大的项目。
就像刚刚说的,我只想有一个js文件加载器,我只需提供给它一个js文件的地址就行了的那种呢?那就进入我们的主题了,使用headjs吧。headjs其实是一整套的工具,但我只想介绍的是它其中的Javascript Loader功能。以下是它的基本用法:
head.js("/path/to/file.js");
最简单的用法,提供一个js的文件的地址给它作为参数,然后它就会默默的在背后进行无阻塞的加载了,至于什么时候加载完可用了,谁也不知道。
最基本的用法,除了提供一个地址参数外,还提供一个回调函数作为第二个参数。在js加载完成后,回调用回调函数,你可以把依赖该js的代码写在回调函数里。
head.js("file1.js","file2.js",... "fileN.js");
提供多个js文件地址,这些js会并行的加载,但会按照参数给定的先后顺序执行这些文件,例如即使file2.js比file1.js先加载完成,但它还会一直等到在file1.js加载和执行完后再执行。
并行加载多个js,并按参数顺序执行,所有js准备完成时,执行回调函数。
多个js并行加载,并且谁先加载完就先执行谁
head.js("file1.js").js("file1.js").js("file3.js");
这样的话用headjs来加载js文件基本都够用了,而且还能处理依赖关系。当是如果你继续装B,弄一个网站,巴不得什么特效都用上,这里找一个jquery插件,那里再找一个,总之就是弄非常多的文件,其中又有复杂的依赖关系,那该肿么办?这还用问吗,以上的那几个用法完全能解决。但转念一想,既然装B那就一装到底吧,现在不是流行模块什么的吧,那咱也整个模块吧,但不是像commonJS说的那么复杂,就是定义一个模块,然后规定这个模块是有那几个js文件组成的,其中的依赖关系又如何等等。那就动手吧,headjs使用的是MTI协议,修改下它应该也是没问题的吧。屌丝又装高富帅了,其实说是修改,倒不如说是增加几段代码进去,而且加载依赖等功能完全是用headjs的api实现的。
这里,我给headjs的新增了两个方法,一个是add(name,file,preload)添加模块,参数name是模块名称,file是要用到的js文件地址,如果有多个文件,并且存在依赖关系,则file可以是一个数组,这个数组的里元素就是用到的文件地址,并且按数组元素的顺序进行依赖。第三个参数preload用指定是否预加载模块文件,如果为false,则在使用该模块的时候才会加载文件,为true时则在定义模块时就会立即加载所用到的文件,默认为false
另一个是use(name,callback),这个方法用来使用模块。name是用add()方法定义的模块名,callback是该模块已经加载完成后调用的回调函数。
于是我们就可以这样来使用headjs了:
如果模块很多,则模块的定义代码可以单独写在一个文件里,并且引入了headjs的后,就立即加载该模块定义文件。这个过程可以很简单的像这样来实现:
看到那个init属性没有,我把它叫做初始化属性,init的值表示文件名,例如上面init就代表与headjs同目录的init.js这个文件。所谓的初始化就是在使用use()之前,init文件一定是已经加载好了的。所以可以把模块的定义写在初始化文件中。
尼玛,这是要闹哪样啊,怎么又多了个main属性,好吧,我承认是看到别人有这个东西于是手贱也跟风弄了一个。这个main属性代表的是模块名,就是head.js与init.js文件都加载完成后,就会自动执行main属性指定的模块(当然要先在init中定义该模块)。所以有了这两个东东后,我们就可以在页面没有一句js代码的情况下(除了引入headjs那段标签),执行很复杂的代码了。
还有一个要说明的地方,就是模块文件的存放位置。模块文件应该和head.js存放在同一个目录,比如head.add(‘a','a.js'),这里的a.js的路径是和head.js相同的,就是说模块文件的路径是相对于head.js存放的路径的,而且只可以往下走,不可以往上走,比如:
head.add(‘a','a/a.js')//正确
head.add(‘a','../a.js')//错误,不能往上定位