这就好像黑板风格,各路专家都可以将自己的知识在黑板上进行展示。
1、基础页面(黑板)提供基本功能,并对外暴露抓手
2、具体控件(专家)在需要运行时,动态在黑板上进行注册,进而可以使用黑板
3、也可以在有需要的时候,让黑板加载额外的JS
我描述一下背景:
我们做的一个BS项目,有一个GIS页面,是公用的。基本上,所有模块,所有功能,都或多或少要用到地图,将自己的结果展示在地图上,甚至与地图交互。类似这样(船讯网不是我弄的,下图仅仅是个示意):

中间这个地图页面,实际上是一个独立的iframe,原因是要保持其独立性和纯洁性,避免被其他页面的样式、JS所污染。
那么就有一个问题,这些需要与地图交互的模块的代码,写在什么地方?因为arcgis for jsapi,有一定的封闭性。
有2种方式:
1)统一写在地图页面,方便地图调用
2)写在每个模块自己的页面,地图页面暴露一些接口,每个模块将自己的具体实例注入,由地图统一调用
我认为首选应该是方式二。理由如下:
1)维持地图页面的代码精简
2)避免资源浪费
每个模块的代码,基本上别的模块用不着,如果都堆在地图页面,没有必要,还会拖慢加载的速度。
如何实现方式二?
一、在GIS页面提供一个方法,让其他模块能注入实例
这就是所谓暴露抓手了。
var map;
var iMap = {};//外部接口
require(["esri/map",
"dojo/_base/array",
"dojo/domReady!"], function (Map,arrayUtils) {
(function(){//加载底图等
map = new Map({
basemap: 'streets',
});
})();
/* 外部接口 by chenqu */
iMap.drawHandler = new (function(){//绘制接口
/*
外部绘制插件,应该实现两个接口:
draw(data, option),绘制
clear(),擦除
*/
this.push = function(mode,bean){//注入外部插件
if(find(mode) == null) {
beans.push({
mode: mode,
bean: bean
});
}
};
this.draw = function (data, option) {//绘制
var beanJ = find(option.mode);
beanJ.bean.draw(data,option);
};
this.clear = function(mode){//清除
if(typeof mode != 'undefined'){//擦除特定插件的绘制
var beanJ = find(mode);
beanJ.bean.clear();
} else {//全部擦除
for(var i in beans){
beans[i].bean.clear();
}
}
};
/* 私有部分 */
let beans = [];//{mode,bean}
function find(mode) {
if (beans.find) {//支持数组 find 方法
return beans.find(function (b) {
return b.mode == mode;
});
} else {
var newArr = arrayUtils.filter(beans, function (t) {
return t.mode == mode;
});
return (newArr.length > 0) ? newArr[0] : undefined;
}
}
})();
});
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
很简单,原理主要是地图页面这里,提供了一个方法:iMap.drawHanlder.push,可以让其他模块将实例注入到内部数组beans中。
当然为了实现这个注入,会有一些辅助的函数,例如查找数组元素,避免重复注入之类。
二、其他模块与地图的交互
控件注册制
let mapWin = getMapWin();//自定义函数,获得底图页面,实现代码略过不提
let require = mapWin.require;
require(["plugin/HeatMap"],function(HeatMap){
var handler = mapWin.iMap.drawHandler;
handler.push("heatmap",new HeatMap(mapWin.map));//注入某个插件。这个插件代码略过不提
handler.draw(data, {//绘制
mode: 'heatmap', node: {}
});
});
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
arcgis for jsapi一般都用AMD这种模块化开发方式,各个模块可以利用地图页面的require:
let mapWin = getMapWin();//自定义函数,获得底图页面,实现代码略过不提
let require = mapWin.require;
require(["plugin/HeatMap"],function(HeatMap){
}
- 1
- 2
- 3
- 4
依赖倒置是设计模式的基础,但本身应该不是设计模式。我实在不知道怎么描述这种开发方式,就拟了上面这个标题。
2020.1.3
三、动态加载JS
/*
地图页面加载气泡相关js
之所以动态加载,是因为气泡相关js不是地图必须依赖,只跟具体业务有关
*/
var script = doc.createElement("script");
script.type = "text/javascript";
// script.onload = function(){
// alert(document.getElementById("frame2D").contentWindow.getTitle("全世界无产阶级联合起来实现共产主义一起走进新时代!"));
// };
script.src = /*[[@{/js/onemap/bubble.js}]]*/"/js/onemap/bubble.js";
doc.getElementsByTagName("head")[0].appendChild(script);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11



















