layout: post

title: 使用requirejs编写模块化代码

category: javascript

date: 2016-10-22 00:00:00

tags:

  • javascript
  • requirejs

写在前面

最早接触javascript的时候,javascript代码直接扔在script标签里面就完事了。

反正代码不多,交互简单,逻辑不难,和HTML混在一起也未尝不可。

后来交互越来越复杂,代码越多越多了,我们就开始把JS代码独立到了单独的JS文件中。

公共的库引用在前,自己的逻辑代码引用在后,全局变量定义在HTML内部,在独立JS文件中直接使用变量就好。

我们会经常看到下面这种代码:

  <script src="1.js"></script>
  <script src="2.js"></script>
  <script src="3.js"></script>
  <script src="4.js"></script>
  <script src="5.js"></script>
  <script src="6.js"></script>

通过script标签顺序去js管理依赖关系。

阮一峰老师在Javascript模块化编程(三):require.js的用法

一文中总结了这样写法的缺点:

首先,加载的时候,浏览器会停止网页渲染,加载文件越多,网页失去响应的时间就会越长;

其次,由于js文件之间存在依赖关系,因此必须严格保证加载顺序(比如上例的1.js要在2.js的前面),依赖性最大的模块一定要放到最后加载.

当依赖关系很复杂的时候,代码的编写和维护都会变得困难。

而requirejs的诞生便是为了解决这个问题。

requirejs

官网把requirejs 下载回来之后。使用一般的方法引入:

<script src="js/require.js"></script>

但是这样的方法,还是可能在加载require.js的时候导致网页失去响应。解决方案一般有两种:

  1. 把上面的代码放到网页底部

  2. 使用异步的方法加载,如下:

<script src="js/require.js" defer async="true" ></script>

async属性 表明这个文件需要异步加载,避免网页失去响应。

不过IE下不支持这个属性,只支持defer,所以可以把defer也写上。

加载主模块

在上一步,我们已经引入了require了,那么require怎么知道我们究竟要加载什么东西呢?答案是使用data-main属性。

假设我们的主模块为js/home.js,引入代码应该如下:

 <script src="js/require.js" data-main="js/home"></script>
//require.js默认文件后缀为js,所以home.js可以写成home。

接下来我使用58HouseSearch 的代码来讲解一下require的使用。

在此项目里面,重构前大概就是JS变量漫天飞,js文件里面各种函数到处乱放。一开始用起来还没什么,后来加入了更多功能的时候,JS代码维护起来就疼不欲生了。因此托了个小伙伴帮忙使用模块化思想重构了一下JS代码。

上面说了,我们首先需要创建我们的模块,在这个项目里面,主模块叫home.js。

home.js中我们需要配置一下require.config.

require.config({
baseUrl: '/DomainJS/',
paths: {
jquery: "lib/jquery-1.11.3.min",
"AMUI": "lib/amazeui.2.7.1.min",
"jquery.range": "lib/jquery.range",
"es5": "lib/es5",
"mapController": "mapController",
"addToolbar": "addToolbar",
},
shim: {
"addToolbar": {
deps: ["jquery"]
},
"jquery.range": {
deps: ["jquery"]
}
}
});

在这里我主要配置了一下baseURL(所有模块的查找根路径),paths(名称映射),shim(

为那些没有使用define()来声明依赖关系、设置模块的"浏览器全局变量注入"型脚本做依赖和导出配置。)

关于require.config的详细内容可以看下下面这些文章:

  1. RequireJS进阶:配置文件的学习
  2. RequireJS进阶:模块的优化及配置的详解

配置做完了,我们也可以开始真正写我们的逻辑代码了,我们使用require来加载我们需要的库。

代码如下:

require(['domready!', 'jquery', 'AMUI', 'mapController', 'city', 'commuteGo'], 

function (doc, $, AMUI, mapController, city, commuteGo) {
city.initAllCityInfo();
mapController.init(); $("input[name='locationType']").bind('click',
mapController.locationMethodOnChange) $("input[name='vehicle']").bind('click', commuteGo.go) $('#Get58Data').bind('click', function(e) {
e.preventDefault(); mapController.Get58DataClick();
e.stopPropagation();
}); $.ajax({
type: "post",
url: "../Commom/GetPVCount",
data: { },
success: function (result)
{
if (result.IsSuccess){
$("#lblPVCount").text(result.PVCount);
}else {
$("#lblPVCount").text(0);
console.log(result.Error);
}
}
}); $('#search-offcanvas').offCanvas({ effect: 'overlay' }); $(".amap-sug-result").css("z-index", 9999);
})

忽略function里面的具体逻辑,加载如下:

require(['domready!', 'jquery', 'AMUI', 'mapController', 'city', 'commuteGo'],
function (doc, $, AMUI, mapController, city, commuteGo){ //todo });

第一个参数为一个数组,表示所依赖的模块,此处为['domready!', 'jquery', 'AMUI', 'mapController', 'city', 'commuteGo'];

第二个参数为回调函数,当前面指定的模块都全部加载成功之后,便调用此函数。加载的模块会以参数形式传入此函数,从而在回调函数内部就可以使用这些模块啦。

require()异步加载所需模块的时候,此时浏览器并不会失去响应;当前面的模块加载成功之后,执行回调函数才会运行我们的逻辑代码,因此解决了依赖性问题。

讲完了模块加载,我们下面讲一下模块编写。

AMD模块编写

require.js加载的模块的采用的AMD规范。所以我们的模块必须按照AMD的规定来写。

关于AMD规范详情可以看这个文章:Javascript模块化编程(二):AMD规范

模块有两个情况,不依赖其他模块和依赖其他模块。

不依赖其他模块

直接define定义,使用function回调。

58HouseSearch/DomainJS/helper.js

define(function () {

    //获取URL中的参数
var getQueryString= function (name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
var r = window.location.search.substr(1).match(reg);
if (r != null) return unescape(r[2]); return null;
}
return {
getQueryString: getQueryString,
};
})

依赖其他模块

define中如同require一样,用数组表明需要加载的模块,function回调。

58HouseSearch/DomainJS/marker.js

define(['mapSignleton', 'city', 'transfer'],
function(mapSignleton, city, transfer) {
var _map = mapSignleton.map;
var _workMarker = null;
var _markerArray = [];
var load = function(x, y, locationName) {
_workMarker = new AMap.Marker({
map: _map,
title: locationName,
icon: 'http://webapi.amap.com/theme/v1.3/markers/n/mark_r.png',
position: [x, y]
});
} var add = function(address, rent, href, markBG) {
new AMap.Geocoder({
city: city.name,
radius: 1000
}).getLocation(address, function(status, result) { if (status === "complete" && result.info === 'OK') {
var geocode = result.geocodes[0];
var rentMarker = new AMap.Marker({
map: _map,
title: address,
icon: markBG ? 'IMG/Little/' +
markBG : 'http://webapi.amap.com/theme/v1.3/markers/n/mark_b.png',
position: [geocode.location.getLng(), geocode.location.getLat()]
});
_markerArray.push(rentMarker); rentMarker.content = "<div><a target = '_blank' href='"
+ href + "'>房源:" + address + " 租金:" + rent + "</a><div>"
rentMarker.on('click', function(e) {
transfer.add(e, address);
});
}
})
}; var clearArray = function() {
if (_markerArray && _markerArray.length > 0)
_map.remove(_markerArray);
_markerArray = [];
} var clear = function() {
if (_workMarker) {
_map.remove(_workMarker);
}
} return {
load: load,
add: add,
clearArray: clearArray,
clear: clear
};
});

这样的话,一个供require调用的模块也就写好了。

最后感谢小伙伴Larry Sean 帮忙重构代码。

全文完。

使用require.js编写模块化JS的更多相关文章

  1. 如何使用 require.js ,实现js文件的异步加载,避免网页失去响应,管理模块之间的依赖性,便于代码的编写和维护。

    一.为什么要用require.js? 最早的时候,所有Javascript代码都写在一个文件里面,只要加载这一个文件就够了.后来,代码越来越多,一个文件不够了,必须分成多个文件,依次加载.下面的网页代 ...

  2. Dojo初探之1:AMD规范,编写符合AMD规范(异步模块加载机制)的模块化JS(其中dojo采用1.11.2版本)

    一.AMD规范探索 1.AMD规范(即异步模块加载机制) 我们在接触js的时候,一般都是通过各种function来定义一些方法,让它们帮我们做一些事情,一个js可以包含很多个js,而这些functio ...

  3. JavaScript模块化-require.js,r.js和打包发布

    在JavaScript模块化和闭包和JavaScript-Module-Pattern-In-Depth这两篇文章中,提到了模块化的基本思想,但是在实际项目中模块化和项目人员的分工,组建化开发,打包发 ...

  4. 前端模块化 、包管理器、AMD、 CMD、 require.js 、sea.js

    问题由来,为什么要前端模块化管理: 假设我们有个组件名为Acomponent.js, 是架构封装的,里面依赖另一个公司公用库common.js: 那我们引入Acomponent.js的时候,怎么知道要 ...

  5. require.js Javascript模块化

    浏览器端的模块,不能采用"同步加载"(synchronous),只能采用"异步加载"(asynchronous).这就是AMD规范诞生的背景. AMD是&quo ...

  6. 【require.js】模块化开发

    一.Require.js及AMD Require.js:是一个非常小巧的JavaScript模块载入框架,是AMD规范最好的实现者之一. AMD(Asynchronous Module Definit ...

  7. AMD模块化JS

    参考http://ourjs.com/detail/52ad26ff127c76320300001f Offcial Site http://requirejs.org/ 下载http://requi ...

  8. 模块化开发(三)---通过node.js学习模块化开发

    由于改文章有点大,部分代码格式有点问题,编辑之后博客园莫名其妙推出,有问题可以留言沟通.   什么是Node? 它是一个在浏览器之外可以解析和执行javascript代码的运行环 境,或者说是一个运行 ...

  9. js的模块化写法

    记得前两天自己写一个动画首页,动画很复杂,我用的fullpage虽然相对比较简单,但是每个页面的animation各有差异,需要相对控制,估计有上千行的js代码,写的心情乱糟糟的. 如何让代码量巨大, ...

随机推荐

  1. 数学建模 TSP(旅行商问题) Lingo求解

    model: sets: cities../:level; link(cities, cities): distance, x; !距离矩阵; endsets data: distance ; end ...

  2. linux shell 获取当前日期/时间

    1. 当前日期 [root@Tomcat DFJR-ERP]# cur_date="`date +%Y-%m-%d`" [root@Tomcat DFJR-ERP]# echo $ ...

  3. spring-boot添加自定义拦截器

    spring-boot中的WebMvcConfigurerAdapter类提供了很多自定义操作的方法,先贴出来大家看看 package org.springframework.web.servlet. ...

  4. [转载]HTML5开发入门经典教程和案例合集(含视频教程)

    http://www.iteye.com/topic/1132555 HTML5作为下一代网页语言,对Web开发者而言,是一门必修课.本文档收集了多个HTML5经典技术文档(HTML5入门资料.经典) ...

  5. 对于最近一星期jsp培训有感

    这周上课是jsp的培训,找的是外面的一个培训机构的讲师,人挺好的,讲的也不错,不过交给我们的任务是一星期做出一个网站模型——新闻发布系统. 由于我们组本科学计算机的人实在太少了,所以这个重担落在我的身 ...

  6. ubuntu环境下eclipse的安装以及hadoop插件的配置

    ubuntu环境下eclipse的安装以及hadoop插件的配置 一.eclipse的安装 在ubuntu桌面模式下,点击任务栏中的ubuntu软件中心,在搜索栏搜索eclipse 注意:安装过程需要 ...

  7. Python练习-内置函数的应用

    说真的,我感觉这几天egon没有睡好,或者是egon心里有事儿,练习给留的太过简单了 # 编辑者:闫龙 # 用map来处理字符串列表,把列表中所有人都变成sb,比方alex_sb #name=['al ...

  8. Eureka简介

    Eureka是Spring Cloud Netfix 的一个子模块,也是核心模块之一,用于云端服务发现.一个基于RestFul的服务,用于定位服务,以实现云端中间层服务发现和中间层转移. 服务注册与发 ...

  9. 网站发布IIS后堆栈追踪无法获取出错的行号

    一.问题起因 系统发布上线后,有时会发生错误,那么错误的记录就很重要,它对于错误的排查和问题的发现有着重要的作用,通常我们采取的方式为Log日志文件记录和数据库错误记录.文本不会讨论错误记录的方式以及 ...

  10. 存储过程简单Demo

    --创建存储过程 delimiter // create procedure p1() begin end // --调用存储过程 call p1(); --删除存储过程 drop procedure ...