原文地址:http://www.sencha.com/blog/integrating-ext-js-with-3rd-party-libraries/
作者:Kevin Kazmierczak
Kevin Kazmierczak is a Senior Technical Architect at Universal Mind, an innovative digital solutions agency that fuses the design capabilities of an interactive firm with the the technical expertise of a systems integrator. He specializes in building frontend applications using Objective-C, HTML/JS, and Flex. Kevin holds an MBA and a BA in Computer Science from Alfred University.
Ext JS提供了大量可高度自定义的直接就可以使用的内部组件。如果组件不在框架中,也可以容易的通过扩展类的方式,甚至通过浏览Sencha市场来获取所需要的组件。这工作可能需要花费大量的时间,有时候为了节省时间,会考虑使用没有包含在Ext JS组件系统的第三方库。针对这种情况,有许多解决方案,而最简单的方法就是创建一个自定义封装组件来处理库,这样就可以在应用程序中实现重用。
封装组件的目的是通过将第三方库所需的逻辑封装起来以方便配置以及与Ext JS框架实现交互。对于在应用程序中使用多少第三方库的API,有很大的自由度。如果库相当简单,且希望对API的访问进行控制,那就可以将API的每一个方法都封装为对应的方法。这样就可以在想要引用额外的自定义逻辑的时候隐藏对不想公开的方法或拦截方法的调用。另一种方式是公开一些API中的根对象,以便其他控件可以自由的通过对象直接调用任何API方法。在大多数情况下,这可能是最终的解决办法,不过,不同的项目会有不同。
为了演示这一方式,将为Leaflet创建一个封装组件Leaflet是一个由Universal Mind的 Vladimir Agafonki创建的开源的Javascript地图库。在应用程序中将使用这个封装组件来显示一张地图,并提供一个按钮来将地图移动到一个指定位置。
Leaflet可以将来自许多不同的地图服务的地图块整合起来,这样就为地图的显示提供了极大的灵活性。在示例中,将使用CloudMade提供的地图块。可以到CloudMade的网站上注册一个免费账号,然后就可在后续的请求(后面的示例需要使用到)中使用获得的API密钥。要想了解更多的与地图块有关的信息,可访问Leaflet的网站。
在应用程序中,首先要做的是在HTML文件中添加库的引用,这样才可以使用库。在示例中,需要在HEAD元素内添加两行来引用Leaflet。在Leaflet快速入门指南的Leftlet安装文档中可获得更多的详细信息。
<linkrel="stylesheet"href="http://cdn.leafletjs.com/leaflet-0.5/leaflet.css"/>
<scriptsrc="http://cdn.leafletjs.com/leaflet-0.5/leaflet.js"></script>
接下来要做的是从Ext.Component扩展出Leaflet的封装组件。Ext.Component会使用一个空白的UI来搭建控件的骨架,不过,它提供了所有所需的框架方法以便让它在任何布局中都能运行得很好。
在集成第三方库的时候,通常都需要配置和初始化它来满足需求。对于示例,需要重写afterRender方法来处理Leftlet的初始化。这个方法会在自定义组件渲染到DOM并准备好与用户交互后运行。还需要添加类的别名和引用地图的配置变量。
Ext.define('Ext.ux.LeafletMapView', {
extend: 'Ext.Component',
alias: 'widget.leafletmapview',
config:{
map: null
},
afterRender: function(t, eOpts){
this.callParent(arguments);
var leafletRef = window.L;
if (leafletRef == null){
this.update('No leaflet library loaded');
} else {
var map = L.map(this.getId());
map.setView([42.3583, -71.0603], 13);
this.setMap(map);
L.tileLayer('http://{s}.tile.cloudmade.com/{key}/{styleId}/256/{z}/{x}/{y}.png', {
key: 'YOUR_API_KEY',
styleId: 997,
maxZoom: 18
}).addTo(map);
}
}
});
var leafletRef = window.L;
if (leafletRef == null){
this.update('No leaflet library loaded');
} else {
....
}
var map = L.map(this.getId());
map.setView([42.3583, -71.0603], 13);
this.setMap(map);
L.tileLayer('http://{s}.tile.cloudmade.com/{key}/{styleId}/256/{z}/{x}/{y}.png', {
key: 'YOUR_API_KEY',
styleId: 997,
maxZoom: 18
}).addTo(map);
到目前为止,已经创建好基本的地图控件了,可以在应用程序中使用了。不过,实际上这还没有完全实现。如果就这样去使用它,会发现它并不是所期望的效果。地图的尺寸并没有填满布局。Leaflet需要随时调用名为invalidateSize()的方法来调整地图的尺寸,并让它渲染成这个尺寸。这个问题在封装组件中很容易解决。可以重写onResize方法来实现,这样,布局的尺寸变化就可以随时调用地图的invalidateSize方法。
添加以下代码到控件:
onResize: function(w, h, oW, oH){
this.callParent(arguments);
var map = this.getMap();
if (map){
map.invalidateSize();
}
}
现在,就可以在布局中使用组件了,而且会看到地图将在提供的布局尺寸内显示。如果布局因浏览器调整尺寸或滑块而改变,将会看到地图应用了新的尺寸。在自定义的封装组件中,通过了几行代码就可以让第三方库Leaflet在Ext JS布局系统运行得很好。
下面创建一个简单的Ext JS应用程序来使用这个新的封装组件。
Ext.Loader.setConfig({
enabled: true,
paths:{
'Ext.ux':'ux'
}
});
Ext.require(['Ext.ux.LeafletMapView']);
Ext.onReady(function() {
Ext.create('Ext.container.Viewport', {
layout: 'vbox',
items: [
{
xtype: 'leafletmapview',
flex: 1,
width: '100%'
}
]
})
});
接下来要做的是处理地图与外部控件的交互。下面将添加一个按钮,当单击它的时候,将地图缩放到一个位置。根据Leaflet文档,这需要调用map对象的setView方法,并纬度和经度的坐标数组以及缩放等级传递给它。所要做的,就是公开封装组件在afterRender方法中创建的map对象,然后在按钮中访问对象并调用它的方法。
在viewport的items数组中地图组件的上面添加以下代码:
{
xtype: 'button',
text: 'Show Buffalo',
listeners:{
click: function(){
var map = Ext.ComponentQuery.query("viewport leafletmapview")[0];
map.getMap().setView([42.8864, -78.8786], 13);
}
}
}
从这里开始,就可以根据自己的需要来实现组件。可以针对所有的安装参数添加配置属性,这样就可以使用Ext JS的配置参数代替第三方库的约定来自定义组件的每一个实例。还可以添加新属性来切换库功能。例如,可以添加一个属性来启用Leaflet的定位功能,这样就可通过浏览器的Geolocation API来找到你的位置。可以在我的GitHub库找到更完整的示例。
所有的库都会有不同,且会出现更多的挑战,不过,这个概念将有助于在Ext JS或Sencha Touch应用程序中整合他们。在Sencha市场或GitHUB已经有许多封装组件,因此可能不需要创建你自己的封装组件。如果找不到所需要的库,那就要创建自己的封装组件,并将它分享到Sencha开发社区。