开发 AMapUI 组件库 高级功能

高级功能 最后更新时间: 2021年01月22日

为了满足UI的个性化需求,UI组件库支持开发者通过“代码”层面的手段来实现功能的改变,而不必局限在组件自身的接口上。一方面,各个组件的实现细节是公开的(比如SimpleMarker),开发者可以参照;另一方面,UI组件库支持通过继承和“模块”替换等方式对组件进行定制修改,从而实现个性化的效果。下面介绍一下UI组件库的实现原理以及如何利用这种实现来进行功能扩展。

模块管理

UI组件库的模块管理基于requirejs(AMD方式),只是封装在AMapUI这个命名空间下。

AMapUI.requirebaseUrl配置指向版本目录,比如1.1的版本目录是:

//webapi.amap.com/ui/1.1

模块的代码文件相对于版本目录的路径(去掉扩展名)即是模块名,比如SimpleMarker的文件地址是:

//webapi.amap.com/ui/1.1/ui/overlay/SimpleMarker.js

那么SimpleMarker模块名即是ui/overlay/SimpleMarker

模块加载

模块加载推荐使用AMapUI.load, 该接口遵循require的语法,即:

AMapUI.load(['path/mod1','path/mod2', ....], function(mod1, mod2, ...){
   //使用加载的模块
});

如果是UI模块(即路径以ui/开头的模块),可以直接使用封装过的AMapUI.loadUI, 同时模块名省略ui/前缀:

//使用loadUI
AMapUI.loadUI(['overlay/SimpleMarker'], function(SimpleMarker){ ... });

//如果使用load,路径要前缀补上'ui/':
AMapUI.load(['ui/overlay/SimpleMarker'], function(SimpleMarker){ ... });

引入多个模块,模块名数组传入多个路径即可,回调函数的参数与路径顺序保持一致:

AMapUI.load(['lib/utils', 'ui/overlay/SimpleMarker'], function(utils, SimpleMarker) {
//调用utils, SimpleMarker
});

预加载

AMapUI.loadUI是一种动态加载的方式,在代码执行时才会加载对应的UI资源;如果您对加载速度较敏感,可以提前引入某个UI模块的script文件,从而加快执行速度。比如:

1.0版本SimpleMarker的模块文件是: //webapi.amap.com/ui/1.1/ui/overlay/SimpleMarker.js,可以在UI组件库的入口文件后提前引入:

<script src="//webapi.amap.com/ui/1.1/main.js"></script>

<!--预加载 SimpleMarker -->
<script src="//webapi.amap.com/ui/1.1/ui/overlay/SimpleMarker.js"></script>

<script type="text/javascript">
//SimpleMarker已经加载,这里loadUI可以立即回调
AMapUI.loadUI(['overlay/SimpleMarker'].....
</script>

复用requirejs

如果您的应用同样依赖 requirejs 做模块管理,可以直接使用UI组件库内部的requirejs,无需另行引入。

//设置自己的require
window.require = AMapUI.requirejs.config({
    context: "my_context",  // 建议设置context,参见 http://requirejs.org/docs/api.html#multiversion
    baseUrl: "...my_mods_path..." // 模块的部署路径
    //...其他requirejs设置
});

//加载自己的mod模块(相对于上述设置的baseUrl)
require(['mod'],function(mod){
   //
});

参见示例

引用内部模块

UI组件库的实现细节是公开的,如果某些内部模块对您的开发有帮助,您同样可以通过AMapUI.load引入这些模块,比如引入UI组件库内部使用的lib/utils

AMapUI.load(['lib/utils'], function(utils) {
    //调用utils的相关方法....
});

不过请注意,尽管可以预期被大量使用的模块不会被轻易改动,但版本变动(需要您手动更新UI组件库的入口文件地址)确实会带来兼容性风险,需要您谨慎对待。

常用的内部模块有:

 

  • lib/$, 即DomLibrary(jQuery或者Zepto)
  • lib/underscore-tpl,underscore语法的模板引擎,包括下列三种语法:   
    • <%- foo %>,html编码后输出
    • <%= foo %>,原值输出
    • <% ..code.. %>,js代码,比如if, for等
  • lib/utils,utils下包含一些常用的工具方法,比如extend,inherit等

继承

通常UI以构造函数类的方式提供,比如SimpleMarker,如果您需要扩展SimpleMarker的能力,可以通过如下的继承方式实现:

//使用load接口引入utils以及目标UI
AMapUI.load(['lib/utils', 'ui/overlay/SimpleMarker'], function(utils, SimpleMarker) {
    
    //新的Marker类
    function MyMarker(opts) {

        //调用父级的构造方法
        MyMarker.__super__.constructor.call(this, opts);

        //..额外的初始化逻辑..
    }

    //继承SimpleMarker的功能
    utils.inherit(MyMarker, SimpleMarker);

    //增加或者覆盖接口
    utils.extend(MyMarker.prototype, {
    //..新的接口
    });
});

参见示例

模块“覆盖”

假设某个UI的界面仅需要微调一下(比如互换两个节点的位置),就能满足您的需求,而该UI自身并没有提供这样的修改接口,UI组件库允许您从代码层面直接“覆盖”掉原来的模块实现。

从requirejs的角度,如果想覆盖模块A的实现, 只要在A模块被引用之前,调用define重新定义即可:

AMapUI.define('模块名',[新的依赖],function(){ 
        //返回新的实现 
});

考虑到代码的执行顺序和书写的方面性,UI组件库允许您提前定义好某个模块的实现,后续加载时,一旦检测到某个模块名已经被定义过,则不再重新定义,从而达到了“覆盖”默认模块实现的目的(更准确的说法是优先使用您的前置定义)

具体而言,UI组件内部普遍采用AMapUI.weakDefine来定义依赖的模块,与原始define的区别是: weakDefine不会覆盖已经存在的模块定义(因此比define要弱)。 如果某个模块在加载之前已经被AMapUI.define过,那么该UI执行的过程中就会使用这个前置定义好的模块实现。

以1.0版本SimpleInfoWindow为例,其代码路径是:

//webapi.amap.com/ui/1.1/ui/overlay/SimpleInfoWindow.js

其中存在如下的dom结构定义:

//注意,这里是weakDefine
AMapUI.weakDefine("polyfill/require/require-text/text!ui/overlay/SimpleInfoWindow/tpl/container.html", [], function() {
    // return  ....html代表的dom结构... 
});

复制该段定义,AMapUI.weakDefine替换为AMapUI.define,第一个参数(模块名)和第二参数(依赖)通常都不需要改动,重新实现第三个function参数(返回新的模块定义):

//完整复制模块名,重新定义该模块的实现,注意,这里是AMapUI.define
AMapUI.define("polyfill/require/require-text/text!ui/overlay/SimpleInfoWindow/tpl/container.html", [], function() {
        //return 新的html结构
});

//加载执行
AMapUI.loadUI(['overlay/SimpleInfoWindow'], function(SimpleInfoWindow) {

    //SimpleInfoWindow此时使用的是新定义的dom结构
});

参见示例

调试模式

为减少请求次数,各UI的代码经过打包处理(即将依赖的模块合并到同一个文件中)。打包后的文件依然有很好的可读性,比如 SimpleMarker。 如果您有兴趣查看UI内部各个依赖模块的原始实现,可以进入“调试”模式,调试模式下UI依赖的模块将逐一单独加载(可以通过浏览器调试工具中的网络请求观察到这一点)。

具体方法是:在当前页面地址上附加get参数debugAMapUI=1(比如这个地址  )。网络请求的变化见如下截图:

正常模式

调试模式,带debugAMapUI=1

返回顶部 示例中心 常见问题 智能客服 公众号
二维码