前段时间粗略的扫过一次require.js,当时没怎么在意,结果昨天看到index里面的代码就傻了,完全不知道从哪开始看啦,所以require与backbone的学习还要加紧才行。
由于前端所占业务越来越重,所以出现了模块化编程,但是js加载的先后顺序可能会给我们带来麻烦。
有时候我们为了解决页面堵塞会采用异步加载js的方式,这种方式往往带来了一些不确定因素。
为了解决这些问题,James Burke 便搞了一个AMD(Asynchronous Module Definition 异步模块定义)规范
异步加载模块,模块加载不影响后续语句执行。
我们这里要学习的require.js就是一个实现了AMD的库,他的提出解决了以下问题:
① 实现javascript异步加载,避免页面假死
② 管理模块之间的依赖性,便于代码编写与维护(这是重点啊)
于是我们一起来学习require.js吧
首先看一看我们的项目文件目录:
我们写下第一段代码:
现在我们的js就需要一个像C语音的main函数,所以我在htm目录再建一个main.js吧
1 <html xmlns="http://www.w3.org/1999/xhtml"> 2 <head> 3 <title></title> 4 <script src="js/require.js" type="text/javascript" data-main="main"></script> 5 </head> 6 <body> 7 </body> 8 </html>
这样我们就成了一个require项目啦。。。需要注意的是这里的
data-main="main"
main指的就是main.js,这个main就是我们传说中的入口函数了。
我先随便在main中写点东西:
alert('刀狂剑痴')
最后我们看看我们的页面:
我们看到他自己引入了main.js,而且是异步的,不会出现阻塞哦。
现在我们换个写法:
1 /// <reference path="js/require.js" /> 2 /// <reference path="js/jquery.js" /> 3 4 require.config({ 5 paths: { 6 jquery: 'js/jquery', 7 test: 'js/test' 8 } 9 }); 10 11 require(['jquery', 'test'], function ($) { 12 alert($().jquery);//打印版本号 13 });
因为我们js文件与htm不是一个目录,所以前面path就在设置目录了,这里首先会加载jquery然后加载我们自定义的test.js。
我们也可以这样写:
1 require.config({ 2 // paths: { 3 // jquery: 'js/jquery', 4 // test: 'js/test' 5 // }, 6 baseUrl: 'js' 7 }); 8 9 require(['jquery', 'test'], function ($) { 10 alert($().jquery);//打印版本号 11 });
反正最后我们完成了第一个例子,现在我们来阶段总结一番:
【阶段总结】
① main使用了config与require,config用于配制一些基本参数,常用:path、baseUrl
② require第一个参数为数组,数组项目为模块名,他们会依次加载,是有一定顺序的
我们这里来搞一个测试,原来不是写了一个图片延迟加载的东东么,我们使用require来试试:
HTML结构:
核心代码:
<script src="js/require.js" type="text/javascript" data-main="main"></script>
main代码:
1 require.config({ 2 baseUrl: 'js' 3 }); 4 5 require(['jquery', 'test'], function ($, imgLazyLoad) { 6 imgLazyLoad($('#con')); //图片延迟加载 7 });
test.js:
1 define(function () { 2 function imgLazyLoad(container) { 3 var imgLazyLoadTimer = null; 4 var resetImglazy = null; 5 container = container || $(window); //需要时jquery对象 6 var imgArr = {}; 7 initImg(); 8 lazyLoad(); 9 autoLoad(); 10 container.scroll(function () { 11 lazyLoad(); 12 }); 13 $(window).resize(function () { 14 initImg(); 15 }); 16 $(document).mousemove(function () { 17 clearTimeout(imgLazyLoadTimer); 18 if (resetImglazy) clearTimeout(resetImglazy); 19 resetImglazy = setTimeout(function () { 20 autoLoad(); 21 }, 5000); 22 }); 23 function initImg() { 24 $('img').each(function () { 25 var el = $(this); 26 if (el.attr('lazy-src') && el.attr('lazy-src') != '') { 27 var offset = el.offset(); 28 if (!imgArr[offset.top]) { 29 imgArr[offset.top] = []; 30 } 31 imgArr[offset.top].push(el); 32 } 33 }); 34 } 35 function lazyLoad() { 36 var height = container.height(); 37 var srollHeight = container.scrollTop(); 38 for (var k in imgArr) { 39 if (parseInt(k) < srollHeight + height) { 40 var _imgs = imgArr[k]; 41 for (var i = 0, len = _imgs.length; i < len; i++) { 42 var tmpImg = _imgs[i]; 43 if (tmpImg.attr('lazy-src') && tmpImg.attr('lazy-src') != '') { 44 tmpImg.attr('src', tmpImg.attr('lazy-src')); 45 tmpImg.removeAttr('lazy-src'); 46 } 47 } 48 delete imgArr[k]; 49 } 50 } 51 } //lazyLoad 52 function autoLoad() { 53 var _key = null; 54 for (var k in imgArr) { 55 if (!_key) { 56 _key = k; 57 break; 58 } 59 } 60 var _imgs = imgArr[_key]; 61 for (var i = 0, len = _imgs.length; i < len; i++) { 62 var tmpImg = _imgs[i]; 63 if (tmpImg.attr('lazy-src') && tmpImg.attr('lazy-src') != '') { 64 tmpImg.attr('src', tmpImg.attr('lazy-src')); 65 tmpImg.removeAttr('lazy-src'); 66 } 67 } 68 delete imgArr[_key]; 69 if (imgLazyLoadTimer) { 70 clearTimeout(imgLazyLoadTimer); 71 } 72 imgLazyLoadTimer = setTimeout(autoLoad, 3000); 73 } 74 } //imgLazyLoad 75 return imgLazyLoad; 76 });
http://sandbox.runjs.cn/show/7vpjps1r
【阶段总结】
这里我们使用了一个新的东西:define
define的参数是一匿名函数,他会有一个返回值,我这里直接返回了函数本身,然后在回调函数中调用之。
我们可以在define中定义一个对象然后返回对象名那么用法就更多了
刚刚看到了一个shim,于是我们这里简单补充一下吧
1 shim: { 2 $: { 3 exports: 'jQuery' 4 }, 5 _: { 6 exports: '_' 7 }, 8 B: { 9 deps: [ 10 '_', 11 '$' 12 ], 13 exports: 'Backbone' 14 } 15 },
shim参数用于解决使用非AMD定义的模块载入顺序问题。
PS:这个是神马意思,我还没完全理解,大概是使用jquery插件时候需要先保证jquery下载才行吧?这里后面再补充。
RequireJs还有许多东西需要学习,今天暂时到这,后面学习时会与backbone整合。
我们现在再回过头看看require解决了什么问题?
因为我们程序的业务由服务器端逐步转到了前端,所以我们的javascript开发变得越发庞大了。
我们需要模块化编程维护着一个个小的单元,比如我们一个复杂的逻辑可能分为几个js。
然后一个复杂的项目结束后可能会有上百个小文件,RequireJS提供了.js进行压缩。
关于压缩相关知识我们后面点再学习啦。。。