说来我学习ArcGIS API也有快一年了,从刚开始的懵懂无知,到自认为还是有点自我看法,前一段时间有个学弟问我,为什么ArcGIS API For JS为什么会基于Dojo开发呢?给他解释了一通也不知道他理解了没有,所以在这里写一篇文章谈谈自己的看法。
一、关于 gis api
首先api是一款类库存在(组件式开发,可能这么不太合适),每个类中都有自己的方法,方法等,涉及到类,就涉及到继承,一个可能需要继承多个,在C#类的多继承是通过接口来实现,而javascript属于原型继承,与强类型的继承有很大的区别,在JavaScript中每个函数(在js中函数即对象)对象都有一个prototype属性,这个属性指向的对象就是这个函数对象的的原型对象(即父类),这个原型对象也有prototype属性,默认指向该原型对象的父类,就这样一级一级形成所谓的原型链这就是原型链的由来,使用原型继承有几个缺点:
- 原型只能为某一个对象,不能设为多个对象(即prototype属性只能指向一个父类),所以不支持多继承
- 原型中的属性为多个子类多共享,如果某个子类修改了原型中的某一个属性值,则其他子类也会受影响
- 原型的设置只能发生在对象都构造完成之后,这样会造成在子类的对象的构造函数中无法修改父类对象的属性,而在基于类的继承中,子类对象在自己的构造函数中可以调用父类的构造函数
为了解决上述问题dojo在js已有的原型的继承机制上进行进一步的封装,可以实现单继承,多继承,这也是dojo的厉害之处,dojo可以快速布局化,这个算是开发效率的方式,使开发人员可以实现快速进行布局,本人没怎么用过,况且还那么丑,还是自己布局好点,况且HTML5有好多布局模块可用,在arcgis api声明自己的模块的时候要用dojo这是他的特色我们应该好好利用。
二、自定义模块
define(["dojo/_base/declare"],function(declare){
return declare(
//类名省略
null,//无父类用null,
{
firstName: "",
middleName: "",
lastName: "",
constructor: function (fName, mName, lName) {//构造函数
this.firstName = fName;
this.middleName = mName;
this.lastName = lName;
},
buyBook: function (bookName, num) {
alert(firstName + " " + middleName + " " + lastName + " want to buy " + num + " " + bookName);
}
}
);
});
define用于定义模块,"dojo/_base/declare"是所以依赖的模块可以有多个。
1.第一个参数className为类名,如示例中的custom.javaworld.Student;
2.第二个参数为该类的父类,dojo中提供了多重继承,当有多个父类时,使用[superClass1,superClass2,...]格式,示例中值为null,因为该类不继承自任何类;
return 某个值(属性 函数 或者对象 如果没有return 那加载不出来什么)
三、自定义模块示例
define(["dojo/_base/declare",
"esri/layers/tiled"],
function (declare) {
return declare(esri.layers.TiledMapServiceLayer, {
constructor: function () {
this.spatialReference = new esri.SpatialReference({ wkid: 4326 });
this.initialExtent = (this.fullExtent = new esri.geometry.Extent(-180.0, -90.0, 180.0, 90.0, this.spatialReference));
this.tileInfo = new esri.layers.TileInfo({
"rows": 256,
"cols": 256,
"compressionQuality": 0,
"origin": {
"x": -180,
"y": 90
},
"spatialReference": {
"wkid": 4326
},
"lods": [
{ "level": 2, "resolution": 0.3515625, "scale": 147748796.52937502 },
{ "level": 3, "resolution": 0.17578125, "scale": 73874398.264687508 },
{ "level": 4, "resolution": 0.087890625, "scale": 36937199.132343754 },
{ "level": 5, "resolution": 0.0439453125, "scale": 18468599.566171877 },
{ "level": 6, "resolution": 0.02197265625, "scale": 9234299.7830859385 },
{ "level": 7, "resolution": 0.010986328125, "scale": 4617149.8915429693 },
{ "level": 8, "resolution": 0.0054931640625, "scale": 2308574.9457714846 },
{ "level": 9, "resolution": 0.00274658203125, "scale": 1154287.4728857423 },
{ "level": 10, "resolution": 0.001373291015625, "scale": 577143.73644287116 },
{ "level": 11, "resolution": 0.0006866455078125, "scale": 288571.86822143558 },
{ "level": 12, "resolution": 0.00034332275390625, "scale": 144285.93411071779 },
{ "level": 13, "resolution": 0.000171661376953125, "scale": 72142.967055358895 },
{ "level": 14, "resolution": 8.58306884765625e-005, "scale": 36071.483527679447 },
{ "level": 15, "resolution": 4.291534423828125e-005, "scale": 18035.741763839724 },
{ "level": 16, "resolution": 2.1457672119140625e-005, "scale": 9017.8708819198619 },
{ "level": 17, "resolution": 1.0728836059570313e-005, "scale": 4508.9354409599309 },
{ "level": 18, "resolution": 5.3644180297851563e-006, "scale": 2254.4677204799655 }
]
});
this.loaded = true;
this.onLoad(this);
},
getTileUrl: function (level, row, col) {
return "http://t" + row % 8 + ".tianditu.cn/cva_c/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=c&TILEMATRIX=" + level + "&TILEROW=" + row + "&TILECOL=" + col + "&FORMAT=tiles";
}
});
});
四、如果引用自定义模块
1、dojoConfig参数解释
var dojoConfig = {
baseUrl: "/js",
has: {
//用于定义dojo的火狐浏览器bug检测模块
"dojo-firebug": true,
"dojo-debug-messages": true
},
//用于定义dojo核心示范异步加载,true:异步,false:同步
async: true,
//如果为true则立即加载deps数组中所有的依赖JS,如果为false则忽略deps数组
parseOnLoad: false,
//用于页面加载时立即加载的JS依赖
deps: ["dojo/parser"],
//这个方法与deps关联,执行这个回调方法直到deps项加载完毕
callback: function(parser) {},
//加载一个模块的请求超时时间,如果超时说明加载模块失败
waitSeconds: 5,
//如果为true可以避免模块缓存(原理就是在请求模块的URL加上当前时间戳)
cacheBust: true
}
2、加载模式
-
通过packages数组进行定义预置AMD模块
//name是该模块标识符名称,localtion为模块所在的路径
var dojoConfig = {
packages: [
{ name: "package1", location: "../lib/package1" },
{ name: "package2", location: "/js/package2" }
]
};
如果这个模块的路径是在根目录下的子目录,我们可以这样定义:
//获取当前项目根目录+模块所在目录
packages: [{
name: "js",
location: location.pathname.replace(//[^/]*$/, '') + '/js'
}]
这种方式加载最为常用,可以引入多个模块,dojoConfig配置必须放在arcgis api的js文件之前否则会出错,
五、在require引入示例
<script type="text/javascript">
var path = this.location.pathname.replace(//[^/]+$/, "");
var dojoConfig = {
parseOnLoad: true,
packages: [{
"name": "MapCluster",
"location": path + "/lib"
}]//都在一个位置写一个即可
};
</script>
<script src="https://js.arcgis.com/3.24/"></script>
<!-- <script src="http://localhost/arcgis_js_api/library/3.20/3.20/init.js"></script>-->
<!--<script src="../../../Scripts/jquery-1.7.1.js"></script>-->
<!--<script src="../../../Scripts/jsapi_vsdoc12_v38.js"></script>-->
<script src="data.js"></script>
<script type="text/javascript">
var map;
var data = [];
var currpage = 1, pagesize = 10, total = 1000;
var pagenum = total / pagesize;
if (total / pagesize != 0) {
pagenum = parseInt(total / pagesize) + 1;
}
require(["dojo/parser",
"esri/SpatialReference",
"dojo/_base/array",
"esri/map",
"esri/layers/ArcGISTiledMapServiceLayer",
"esri/geometry/Point",
"esri/layers/GraphicsLayer",
"MapCluster/ClusterLayer",
"MapCluster/BDAnoLayer",
"MapCluster/BDImgLayer",
"MapCluster/BDVecLayer",
"MapCluster/TDTTilesLayer",
"esri/graphic",
"esri/symbols/SimpleMarkerSymbol",
"esri/symbols/SimpleLineSymbol",
"esri/symbols/SimpleFillSymbol",
"esri/renderers/ClassBreaksRenderer",
"dojo/_base/Color",
"esri/geometry/webMercatorUtils",
"dojo/domReady!"],
function (parser,
SpatialReference,
arrayUtils,
Map,
Tiled,
Point,
GraphicsLayer,
ClusterLayer,
BDAnoLayer,
BDImgLayer,
BDVecLayer,
TDTTilesLayer,
Graphic,
SimpleMarkerSymbol,
SimpleLineSymbol,
SimpleFillSymbol,
ClassBreaksRenderer,
Color,
webMercatorUtils) {
红线标注是在require中引入,因为四个自定模块都在一个文件下,所以在dojoConfig配置一项即可。