Dojo是一套工具,用来构建更好的基于浏览器的应用程序。Dojo绝大部分使用客户端Javascript语言来构建,大大扩展了现代浏览器的能力。它是一系列静态客户端JavaScript脚本,不需要任何的客户端插件和服务器组件。Dojo是开源的框架,也是面向对象的框架,使用起来非常方便,同时也有很绚丽的界面效果,它也符合现在RIA技术的潮流。
为什么要整理Dojo呢?因为ArcGISfor javascript API是基于Dojo框架的,或者说它是在Dojo的基础上搭建的,使用了大量的Dojo技术,因此,Dojo也是ArcGIS for javascript API程序设计的基础。本文整理的资料为简单的Dojo使用,只是满足了ArcGISfor javascript API开发的条件,我也没有深入学习和研究Dojo。
一、Dojo的组成
Dojo包含以下三个项目。
Dojo:是Dojo的基础,所有其他的功能都建立在其上。总之,他包含大约50个Javascript脚本和几个其他资源。这些资源用于处理浏览器差异的统一、Javascript模块化、Javascript核心库扩展、W3C DOM API扩展(包括解析和查询DOM)、远程脚本编程、Firebug Lite、拖放、数据存储API、本地化和国际化,以及一些其他的附加功能。
Dijit:Dojo的小部件框架和内建的小部件集(大约40个HTML用户界面小部件)。可以理解为可视化组件库。
Dojox:Dojo扩展库。这包含了从表格小部件到绘图库德所有功能。这里有许多非常精妙、稳定和已经为实际盈利项目所使用的程序库,同时也有很多完全属于试验阶段的系统。每个Dojox库都具备一份自述文件来描述其功能。
这三个项目保存在各自的源代码目录中。一般而言,Dojo和Dijit同时发布。现在,虽然Dojox曾与Dojo和Dijit一起发布,但是这种情况在将来可能会发生改变。
二、使用Dojo
1、安装Dojo
技术上讲,Dojo是客户端JavaScript工具包,其核心是一些高度优化的JavaScript脚本。Dojo不需要Web服务器,Dojo是完全与服务器端无关的,它不会因为使用Windows、Linux还是Max OS X服务器而需要任何特殊处理。你可以在任意一个目录下安装Dojo,建立基于Dojo的Web应用程序,并用file://协议载入这些程序。在HTML页面上,一般使用<script>标签载入Dojo组件。 可以从http://dojotoolkit.org下载最新的Dojo包。包中捆绑了Dojo、所有的Dijit组件和Dojox扩展组件。目前最新的版本是v1.5。根据提示把Dojo包下载后,解压到你的电脑上,一般文件夹的名字是Dojo加上当前的版本号。
2、把Dojo添加到网页
使用Dojo和dijit时,需要把Dojo包放到当前网站目录下后,然后在需要的HTML页面上添加一些语句即可,具体步骤如下:
1)添加标准的Dojo首部
代码
<style type="text/css">
@import "dojo-release-1.5.0-src/dijit/themes/tundra/tundra.css";
</style>
<script type="text/javascript" language="javascript" src="dojo-release-1.5.0-src/dojo/dojo.js"
djConfig="parseOnLoad:true"></script>
或者:
1 <script type="text/javascript" language="javascript" src="dojo-release-1.5.0-src/dojo/dojo.js" djConfig="parseOnLoad:true"></script>
2 <link type="text/css" href="dojo-release-1.5.0-src/dijit/themes/tundra/tundra.css"rel="Stylesheet"/>
3
注意:如果使用Dijit,则必须导入dojo.css:
1 <link type="text/css" href="dojo-release-1.5.0-src/dojo/resources/dojo.css" rel="Stylesheet"/>
2)为body标签设置样式类
1 <body id="body" class="tundra">
3)添加dojo.require语句
Dojo和Dijit组件被装在一个个小包裹里面,他们被称为模块,你在网页中每引用一个模块就必须写一句dojo.require来把相应的模块添加到网页中:
1 <script type="text/javascript" language="javascript">
2 dojo.require("dojo.parser");
3 dojo.require("dijit.layout.ContentPane");
4 </script>
5
3、在网页中使用Dojo和Dijit组件
完成以上三步之后,你就可以使用Dojo进行开发了。要在HTML页面中使用dojo和dijit组件,一般有两种方法:使用声明式小部件和编程式小部件。为了说明这两种方式,写一个在网页中创建Windows程序中经常使用的Tab控件的例子。
1)声明式小部件
简单的说,声明式小部件是像这样的HTML:
<div id="tabContainer" dojoType="dijit.layout.TabContainer" >
声明式小部件使用非标准HTML属性,如dojoType=。dojoType就是指定了当前html标签所要使用的dijit的部件。声明式小部件是使用Dijit最简易的方法,在使用时一定要注意以下几点: 一、无论使用什么样的主题都必须导入dojo.css;二、使用dojo.require(“dojo.parser”)加载dojo.parser模块,并在添加首部标签时使用djConfig=”parseOnLoad:true” 。
代码
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>dojoDemo</title>
<link type="text/css" rel="Stylesheet" href=dojo-release-1.5.0-src/dijit/themes/tundra/tundra.css"/>
<link type="text/css" rel="Stylesheet" href="dojo-release-1.5.0-src/dojo/resources/dojo.css"/>
<script type="text/javascript" language="javascript" src="dojo-release-1.5.0-src/dojo/dojo.js" djConfig="parseOnLoad: true"></script>
<script type="text/javascript" language="javascript">
dojo.require("dijit.layout.ContentPane");//加载ContentPane部件
dojo.require("dijit.layout.TabContainer");//加载TabContainer部件
</script>
<body class="tundra">
<div class="formContainer" dojoType="dijit.layout.TabContainer" style="width:400px;height:100px">
<div dojoType="dijit.layout.ContentPane" title="页面一">
<div>这是页面一</div>
</div>
<div dojoType="dijit.layout.ContentPane" title="页面二">
<div>这是页面二</div>
</div>
<div dojoType="dijit.layout.ContentPane" title="页面三">
<div>这是页面三</div>
</div>
</div>
</body>
</html>
效果如下:
2)编程式小部件
编程式小部件是用Javascript代码创建的:
1 var programmaticPane=new dijit.layout.ContentPane({href:'http://www.yahoo.com'});
TabControl的Demo如下:
代码
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>dojoDemo</title>
<link type="text/css" rel="Stylesheet" href="dojo-release-1.5.0-src/dijit/themes/tundra/tundra.css"/>
<link type="text/css" rel="Stylesheet" href="dojo-release-1.5.0-src/dojo/resources/dojo.css"/>
<script type="text/javascript" language="javascript" src="dojo-release-1.5.0-src/dojo/dojo.js" djConfig="parseOnLoad: true"></script>
<script type="text/javascript" language="javascript">
dojo.require("dijit.layout.ContentPane");//加载ContentPane部件
dojo.require("dijit.layout.TabContainer");//加载TabContainer部件
var total;
var programmaticPane=new dijit.layout.ContentPane({href:'http://www.yahoo.com'});
function addTab()
{
var tabContainer=dijit.byId("tabContainer");//得到tabContainer
total = tabContainer.containerNode.childNodes.length;//得到当前tabContainer中的tab数量
var tab=new dijit.layout.ContentPane();//新建Tab
tab.title="页面"+total;//设置Tab的title
tabContainer.addChild(tab,0);//把Tab添加到tabContainer中
}
</script>
<body class="tundra">
<input type="button" value="添加Tab页" οnclick="addTab()" />
<div id="tabContainer" dojoType="dijit.layout.TabContainer"></div>
</body>
</html>
每当点击“添加Tab页”按钮,就会在TabContainer中新增加一个Tab页面
三、Dojo的事件机制
Dojo提供了一个DOM事件框架,改框架在所有Dojo支持的浏览器中具有一致的行为。
1、事件驱动编程模型
事件发生时,将调用一个函数——称为处理函数(handler)。事件有时被称为信号(singnal),可能是一个硬件事件,例如鼠标手势;或者一个软件事件,例如提交表单。处理函数又被称为监听器(listener)或回调函数(callback),是一个拥有明确定义的参数集合并在明确定义的上下文中执行的函数。下图是浏览器中的事件处理模型。
2、 管联处理函数
Dojo提供了一个用来关联处理函数与DOM事件的dojo.connect方法。这个函数是Dojo事件框架的关键,它使事件处理函数按我们所描述的那样去执行,而且不依赖于任何特定的浏览器,签名如下:
handle=dojo.connect(obj,event,context,handler)
给一个按钮添加事件:
代码
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/--> 1 <input type="button" value="点击我" id="btn"/>
function init()
{
dojo.connect(dojo.byId("btn"),"click",clickHandler);
}
function clickHandler(event)
{
alert("点击了!");
}
dojo.addOnLoad(init); //加载Dojo后触发
3、事件传播
对于有些事件,浏览器会把一个事件分派到多个DOM节点,这一过程称为事件传播。处理函数可以影响事件的传播。
一般点击事件的过程是,当用户点击一个DOM节点时,一个点击事件被发送到目标节点(目标节点就是事件发生的节点)、它的父节点、祖父节点等等,一直到文档树的最上层。这个发送过程称为冒泡(bubbing)。无论对错,W3C事件规范中规定,一些事件不能完全地冒泡下去,Dojo也没有改变这种行为。
与冒泡的工作方式相反的是捕获(capturing),它从目标对象的最远祖先开始一致到目标对象的父节点,依次调用他们的事件处理函数。
冒泡可以使我们将代码统一放到父节点。例如,假设我们有一个div节点,它包含有100个子节点,每个子节点在结构上都是一致的并都使用同一个点击事件处理函数。我们可以为每一个子节点都关联这个处理函数,也可以只为他们的父节点div关联这个处理函数。父节点所关联的处理函数要检查事件对象的target属性,以此确定实际被点击的子节点。这个解决方法显然更胜一筹。
有时你可能想阻止冒泡行为,那么在事件监听器中添加这样的代码:
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/-->1 function someHandle(eventObj)
{
//处理事件
//停止冒泡
eventObj.stopPropagation();
}
因此,DOM的事件传播路径顺序如下:
1、捕获阶段:从最远祖先开始到父节点未知,调用目标节点祖先的处理函数。
2、调用目标节点的处理函数。
3、冒泡阶段:从父节点开始到最远祖先为止,调用目标节点祖先的处理函数。
当一个处理函数被关联到一个事件时,它或者被关联到捕获阶段,或者被关联到冒泡阶段,如果想在两个阶段都看见这个事件发生,就要为两个阶段各关联一个处理函数。
下面的图能加深对这种DOM事件传播机制的理解。
对上图的理解:当<tbody>的一个<td>触发一个事件Event后,先是执行捕获阶段,也就是图上红色的流程:DefaultView-->Document-->...--><tr>。然后调用目标节点的处理函数,即图上蓝色的流程,最后执行冒泡阶段:<tr>--><tbody>-->…-->DefaultView。这样一个事件Event的流程就结束了。
关于冒泡和捕获,在W3C的官方网上有详细说明:http://www.w3.org/TR/2009/WD-DOM-Level-3-Events-20090908/。
四、简单的Dojo AJAX编程
在Dojo的XHR(XHR就是XMLHttpRequest对象)框架中的核心函数是:dojo.xhrGet、dojo.xhrPost、dojo.rawXhrPost、dojo.xhrPut、dojo.rawXhrPut和dojo.xhrDelete,这些函数分别对应于GET、POST(包括两种变体)、PUT(包括两种变体)以及DELETE这些HTTP方法。这些函数统称为dojo.xhr*函数。
我用的最多的就是dojo.xhrGet函数。在ArcGISAPI for JavaScript编程中,经常使用这个函数来调用Rest API,所以我主要记录了这个函数的用法。在使用该函数时,需要传进去一个叫做args的参数散列,args中包含了对请求的完整描述。这个args散列的具体内容如下:
1、url(字符串):一般情况下,URL不会包含用户名或密码相关的内容,也不会再路径后附加内容,比如参数或者查询字符串。
2、load:当请求成功完成时调用的函数。
3、error:当请求失败时调用的函数。
4、handleAs(字符串):指定如何预处理响应。默认的处理是将响应作为文本来进行处理。
5、sync(布尔值):指定同步还是一部发送XHR,默认的处理是异步发送。
6、preventCache(布尔值):指定是否阻止对返回的资源进行缓存,默认是不阻止。
下面是一个例子,向服务器请求当前服务器的日期,返回的日期用对话框显示。
HTML页面:
代码
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/--> 1 <body>
<input type="button" value="得到时间" οnclick="getTime()" />
</body>
Javascript代码:
function getTime()
{
dojo.xhrGet({
url:"Server.aspx",//服务器指向
load:succesHandler,//请求成功完成后的回调函数
error:errorHandler,//请求失败的回调函数
handleAs:"text"//返回数据的格式
});
}
function succesHandler(response)
{
alert(response);
}
function errorHandler(errorResponse)
{
alert(errorResponse.message);
}
如果返回的是JSON格式的数据的处理如下。
Server端:
代码
using System;
public partial class Server : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string json = "{\"name\":\"Carlbiao\",\"age\":21,\"school\":\"西北农林科技大学\"}";
Response.Write(json);
}
}
JavaScript脚本:
代码
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/--> 1 function button_click()
{
dojo.xhrGet({
url:"Server.aspx",//服务器指向
load:succesHandler,//请求成功完成后的回调函数
error:errorHandler,//请求失败的回调函数
handleAs:"json"//返回数据的格式
});
}
function succesHandler(response)
{
alert("姓名:"+response.name+"\n"
+"年龄:"+response.age+"\n"
+"学校:"+response.school);
}
function errorHandler(errorResponse)
{
alert(errorResponse.message);
}
可以看到,要想返回的数据为JSON,把handleAs后的参数改为”json”即可。
由此可见,和我整理的第一篇关于Ajax机制的文章中的使用原始的XMLHttpRequest对象来编写Ajax程序相比,dojo的XHR框架为我们提供了强大而简单的功能。首先,它屏蔽了不同浏览器对Ajax Engine的不同的支持;其次,它不再需要我们去判断XMLHttpRequest的就绪状态等等信息,把成功时的回调函数和失败时的回调函数分得清清楚楚,且回传信息清晰;最后,它也支持不同的数据格式。
现在大多数的开发者都不愿意直接使用XMLHttpRequest对象进行Ajax开发,都会借助第三方的框架。道理很简单:简化代码,避免错误。
在这里,我还有一些疑惑希望大家能帮帮我。
1、如果使用ArcGIS Rest API,大家在客户端一般使用什么样的异步调用方法呢?
2、现在的大部分浏览器还支持跨域请求,但是以后这将收到限制,那么,如果网站上需要进行跨域请求时,大家怎么做呢?是使用Web Service来进行跨域请求,然后再异步返回结果,还是其他的方式呢?
Dojo的功能十分强大,我这里也只是整理一些基础,这些基础就够我们进行ArcGIS API for Javascript的开发了。下面的本文参考是深入学习Dojo开发的好资料。
本文参考:
1、《精通Dojo》
2、Dojo官方网:http://dojotoolkit.org/
3、W3C官方网:http://www.w3.org