原文地址: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安裝文檔中可獲得更多的詳細資料。
[html]view plaincopy
<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並準備好與使用者互動後運行。還需要添加類的別名和引用地圖的組態變數。
[javascript]view plaincopy
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);
}
}
});
下面逐句來研究一下afterRender的代碼:
[javascript]view plaincopy
var leafletRef = window.L;
if (leafletRef == null){
this.update('No leaflet library loaded');
} else {
....
}
在這裡嘗試在window.L命名空間中訪問Leaflet庫。如果不能擷取到庫的引用,就使用一個資訊來更新群組件的html,提示載入庫時出錯。
[javascript]view plaincopy
var map = L.map(this.getId());
這裡將傳遞Ext JS的組件id來建立Leftlet地圖對象。預設情況下,由Ext.Component建立的HTML標記是DIV,而這正是Leaflet用來初始化地圖組件所需的。在這裡使用的是在渲染控制項時Ext架構產生的id,而不是使用硬式編碼id來引用DIV。這樣的好處就是可以在應用程式中建立多個執行個體。
[javascript]view plaincopy
map.setView([42.3583, -71.0603], 13);
這句將地圖的位置設定為麻薩諸塞州的波士頓的緯度和經度,地圖的縮放等級為13。有許多線上工具可以用來尋找不同地點的緯度和經度。
[javascript]view plaincopy
this.setMap(map);
將地圖引用設定給map變數,這樣就可在後續代碼中使用它來訪問地圖。
[javascript]view plaincopy
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使用CloudMade的地圖塊。假設你已經建立了一個帳號並註冊了你的應用程式,你就可以將得到一個API密鑰放到YOUR_API_KEY中。不用去擔心那個混亂的網址,當移動地圖的時候,Leaflet會動態去載入地圖塊。如果需要瞭解更多的資訊,建議查看Leaflet的API文檔。
到目前為止,已經建立好基本的地圖控制項了,可以在應用程式中使用了。不過,實際上這還沒有完全實現。如果就這樣去使用它,會發現它並不是所期望的效果。地圖的尺寸並沒有填滿布局。Leaflet需要隨時調用名為invalidateSize()的方法來調整地圖的尺寸,並讓它渲染成這個尺寸。這個問題在封裝組件中很容易解決。可以重寫onResize方法來實現,這樣,布局的尺寸變化就可以隨時調用地圖的invalidateSize方法。
添加以下代碼到控制項:
[javascript]view plaincopy
onResize: function(w, h, oW, oH){
this.callParent(arguments);
var map = this.getMap();
if (map){
map.invalidateSize();
}
}
這樣,布局的改變且有一個有效地圖引用就可以隨時進行調用。如果調整了尺寸,就會告訴Leaflet去執行invalidateSize方法。
現在,就可以在布局中使用組件了,而且會看到地圖將在提供的布局尺寸內顯示。如果布局因瀏覽器調整尺寸或滑塊而改變,將會看到地圖應用了新的尺寸。在自訂的封裝組件中,通過了幾行代碼就可以讓第三方庫Leaflet在Ext JS布局系統運行得很好。
使用樣本
下面建立一個簡單的Ext JS應用程式來使用這個新的封裝組件。
[javascript]view plaincopy
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%'
}
]
})
});
這裡建立了一個viewport來使用整個瀏覽器的尺寸並將地圖渲染到整個視圖。這樣,將會看到一個波士頓地區的大地圖以及一些簡單的縮放控制。
接下來要做的是處理地圖與外部控制項的互動。下面將添加一個按鈕,當單擊它的時候,將地圖縮放到一個位置。根據Leaflet文檔,這需要調用map對象的setView方法,並緯度和經度的座標數組以及縮放等級傳遞給它。所要做的,就是公開封裝組件在afterRender方法中建立的map對象,然後在按鈕中訪問對象並調用它的方法。
在viewport的items數組中地圖組件的上面添加以下代碼:
[javascript]view plaincopy
{
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應用程式中,有許多方式來引用組件,包括控制器的refs、Ext.ComponentQuery()等等。對於當前樣本來說,最方便的是使用組件查詢來找到在viewport中的地圖組件。一旦獲得引用,就可以調用getMap方法來獲得Leaflet的地圖執行個體並直接調用任何Leaflet的APi方法。
從這裡開始,就可以根據自己的需要來實現組件。可以針對所有的安裝參數添加配置屬性,這樣就可以使用Ext JS的配置參數代替第三方庫的約定來自訂群組件的每一個執行個體。還可以添加新屬性來切換庫功能。例如,可以添加一個屬性來啟用Leaflet的定位功能,這樣就可通過瀏覽器的Geolocation API來找到你的位置。可以在我的GitHub庫找到更完整的樣本。
650) this.width=650;" src="http://www.bkjia.com/uploads/allimg/131228/113F14039-0.jpg" />
小結
所有的庫都會有不同,且會出現更多的挑戰,不過,這個概念將有助於在Ext JS或Sencha Touch應用程式中整合他們。在Sencha市場或GitHUB已經有許多封裝組件,因此可能不需要建立你自己的封裝組件。如果找不到所需要的庫,那就要建立自己的封裝組件,並將它分享到Sencha開發社區。