我印象中,js脚本文件的loader似乎有,但是完美的,完美到像php的include或者cSharp的using的,貌似没有。有些团队据说有,但是没有一个公认的好的方式,或者说没有一个团队愿意拿出来共享,我觉得这说明,他们的方法都存在问题:或者代码冗余,或者存在n多不确定性,或者只适用于他们自己的环境。
注意我说的是一个文件的loader,是通过script标记的src属性调用,而不是将js代码通过innerHTML写到一个div或者什么标签里。
为什么要写loader呢?
比如jq的冗长是我们经常诟病的一个问题。我在冒死写我自己的类库的一开始,我就确定了一个事情:分文件写。也就是,一个核心的、公共的类库是必需的,然后根据页面需要挂所需的js文件。我觉得这个出发点还是不错的。但是后来我意识到,比如在ui部分,tab标签、无缝滚动、图片轮显、ajax等等诸多部分分在不同的文件中,而往往首页里这些都要用得到,那么,script标记在页头最多时有10个上下。当然,如果你不在意还行。我觉得有点蠢。
jq的冗长是我不要的,script标记过多也不是我要的,所以,我需要一个loader。
但是我还没想好。
这里只做一个简单的实现,实现通过js添加一个script标记,并且确保这个标记引入的文件会被执行。
想到的方式有两种:通过dom添加和通过document.write直接写。
通过dom方式是最方便、简单,并且标准的方式。只要通过document.createElement创建一个script标记,并且按照html标准添加type和src属性,然后把这个标记添加到页面当中去就可以了。但是如我们所知,如果我们不把具体的js代码放到window.onload当中去的时候,js标记的位置是个很重要的问题。也就是说,你的类库文件必须在前,实例应用必须在其后,不但js是逐行的,ie中html也tmd的是逐行的。在添加js标记时,我选择将标记放到head中。并且,head是一个默认标记,就像document,无论你的html中是否有head代码,head标记都是存在的。所以无需判断head标记是否存在,直接用head.appendChild即可。需要注意的问题有二:1、head的获取,在ie下是需要使用getElementsByTagName(‘head’)[0]来获得,其他浏览器直接document.head即可得到。2、执行顺序ie有所不同。我的感觉:在ie下,ie会重新理解标记位置,按script标记在head中的顺序逐行执行引入的文件;而其他浏览器,是按照引入的时间来执行的,比较复合人类的思路。
通过document.write方式,更直接。我先说一下我最终没有采用dom方式的原因:文件加载完成的时间不确定。我幻想过,当我添加了一个新的script标记后,window.onload事件会再次触发一次。当然事实并不是这样。换句话说,我不知道js文件什么时候能够加载完。而当你document.write的时候,所写入的代码会成为html解析的一部分,所以浏览器会等待js文件加载完成以后再执行下面的解析。需要注意的问题:如果在script标记A中使用document.write写了一个script标记B,那么,标记B会紧跟在标记A之后,也就是说是在标记A的外部。所以,在标记A中不能使用动态写入的标记B中的代码,需要在标记A之外重新写script标记来执行标记B中的代码。
最后附上muselite库里暂时新加的window.using代码,这段代码还没有想好怎么用,仅仅完成了文章开头所说的,动态添加的功能而已。
window.MUSELITE_DEFAULT_FOLDER = 'Scripts'; (function(w, arr){ w._using = function(app){ if(!app || typeof app != 'string') return; var i = 0, len = arr.length; for(; i < len; i++) arr[i] === null ? document.write(app) : document.write(arr[i]); } w.using = function(){ if(arguments.length < 1) return; var i = 0, len = arguments.length; for(; i < len; i++){ w._using(arguments[i]); } } })(window, ['']);
*注意匿名函数执行时的第二个参数,实际为
['<scr', 'ipt type="text/javascript" src="', window.MUSELITE_DEFAULT_FOLDER, '/', null, '.js"></scr', 'ipt>']
被wp的编辑器吃掉了
我更喜欢使用DOM方式添加脚本。
主要的问题在于,使用document.write输出script标签,只能在文档流没有结束前使用。
如果文档已经加载完毕,通过某个事件(例如鼠标点击按钮)加载进一个script,就不能用document.write
至于判断是否加载完,可以用script.onload=script.onreadystatechange=function(){}
script.onload还…真不知道…没想过…mm吉祥。