整合ExtJS和第三方類庫

oschina發表於2013-07-04

 介紹

  ExtJS提供了許多高度可定製化內建元件。如果它不在框架(framework)裡面,你可以很容易的擴充套件這些類,或者瀏覽Sencha市場(Sencha Market)尋找你可能需要的任何東西。那些都在大部分的時間裡執行得很好,但是有時候你興許想要使用一些不是使用ExtJS的元件系統構建的第三方庫。有很多方法可以幫助你解決這個問題,而最簡單的一種方法是建立一個定製的封裝元件,用來處理你的這個庫,這樣它就可以在你的應用中重用了。

  實現概述

  封裝元件的目標就是封裝第三方庫在自我安裝和與Ext JS互動時的邏輯要求。你能很隨意地設定你的應用程式能使用的第三方庫提供的API。在這個問題上,你有以下幾個選項。如果第三方的庫相對比較簡單,而你想控制對API的訪問,那麼你可以封裝每一個API的方法,在你的封裝器裡,你可以封裝成相應的方法。這種方法能允許你隱藏不想暴露的方法,還允許你攔截你引進的附加定製的邏輯函式呼叫。用。另外一種選擇則是暴露一些在API中的根物件,這樣其他的控制元件就能在物件上直接自由地呼叫任何API方法。在大多數情形下,這將可能是你最後的方法,但是所有的專案都不同。

  為了闡述這個觀點,我們將圍繞Leaflet庫建立一個封裝元件。Leaflet是一個開源的地圖Javascript庫,它由Universal Mind的Vladimir Agafonkin建立的。我們將在一個應用程式中使用這個封裝元件。該應用程式給我們展示了一個地圖並提供了一個可以移動到地圖中指定位置的按鈕。

  Leaflet能在不同地圖服務中整合地圖配置檔案,給你在地圖外觀選擇上提供最大的柔韌度。在這個例子中,我們將使用由CloudMap提供的滴入配置檔案。你可以免費註冊一個賬號,獲取API金鑰在你的請求中使用(我們將在這個例子的後面使用)。對於更多的地圖配置檔案的資訊,請訪問Leaflet

  新增庫引用

  在你應用程式中你要做的第一件事就是新增庫對HTML檔案的引用, 這樣庫就能生效並使用。在我們的例子中,我們將新增兩行程式碼到每個Leaflet文件的頭部。你可以在 Leaflet Quick Start Guide中獲得更詳細的安裝細節。

<link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.5/leaflet.css" />
<script src="http://cdn.leafletjs.com/leaflet-0.5/leaflet.js"></script>

  組建定製控制元件

  我們下一步要做的就是擴充Ext元件,為Leaflet建立封裝元件。Ext元件將提供一個大致的,帶有空UI介面的控制元件,但是包含所有框架需要的在任何佈局中都表現出色的方法

  當整合第三方庫的時候,我們通常需要配置和初始化庫來與我們的需求相配。對於我們的例子,在過載'afterRender'方法時,我們將操作Leaflet的初始化。這個方法的執行發生在,我們定製的元件已經被渲染到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);
		}
	}
});

  單步進入 ‘afterRender’ :

var leafletRef = window.L;
if (leafletRef == null){
	this.update('No leaflet library loaded');
} else {
	....
}

  我們嘗試訪問載入在window.L名稱空間的Leaflet庫。如果我們不能獲得庫的引用,我們將更新元件的html檔案,顯示一則宣告存在載入庫檔案錯誤的訊息。

var map = L.map(this.getId());

  在這裡我們建立一個Leaflet地圖物件,把Ext JS元件的ID號傳遞過去。預設情況下,HTML的標籤由Ext建立。 元件將會變為一個div,這是Leaflet初始化地圖控制元件要求做到的。相比硬編碼一個ID給div的引用,我們將使用Ext框架在渲染控制元件時生成的ID號。這允許我們在application.map.setView([42.3583, -71.0603], 13)函式呼叫上擁有多個控制元件的例項。

  這一步就把地圖的緯度/經度設定為麻省州波士頓的位置,並設定放大級別為13。對於不同的locations.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時用CloudMade的地圖配置檔案。假設你建立一個賬號並註冊你的應用程式,你將獲得一個API金鑰,這個金鑰是你要在‘YOUR_API_KEY’裡要提供的。不要擔心迷惑性的URL網址,這是當你移動地圖時,Leaflet將怎樣動態載入你的配置檔案。我建議你去看一看Leaflet API文件。

  此時此刻,你有一個基本的地圖控制元件可以在你的應用中使用。然而,我們完全沒有這樣做。如果你按照現狀來使用,你不會看見你所期待的。尺寸和你的佈局不搭配。Leaflet需要我們去呼叫一個叫做'invalidateSize()'這個方法在每次地圖尺寸發生變化的時候,然後Leaflet就會渲染那個尺寸。這在我們的封裝元件中是個很容易解決的問題。我們可以過載'onResize'方法,這個方法會在佈局中尺寸發生改變時呼叫,並在地圖中呼叫'invalidteSize'方法。

  我們要把如下程式碼新增到我們的控制元件中:

onResize: function(w, h, oW, oH){
	this.callParent(arguments);
	var map = this.getMap();
	if (map){
		map.invalidateSize();
	}
}

  這將會在佈局發生改變時被呼叫,如果我們有一個合法的地圖引用,那麼我們將看到這一點。如果沒有,我們將通過‘invalidateSize’通知Leaflet。

  現在我們可以在佈局中使用元件,你可以看到它會響應我們提供給它的佈局維度。如果佈局因為瀏覽器尺寸改變或者滑動而改變,你將會看到新尺寸會被應用。在我們定製的封裝元件,我們用了行數不多的程式碼,是第三方庫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%'
			}
		]
	})
});

  這將建立一個使用瀏覽器全屏的viewport,並使用全景渲染我們的地圖。你使用一些簡單的縮放控制元件,將會看到一個較大的波士頓地區的地圖。

  下一步要做的就是操作地圖和外部控制元件的互動。我們在地圖上新增一個按鈕,在它被點選的時候讓地圖縮放到一個位置。根據Leaflet文件,你需要做的就是在地圖物件上呼叫'setView',並傳遞經緯度的座標陣列和縮放級別。我們要用我們的封裝元件在我們建立的'afterRender'函式中顯示暴露地圖物件,然後使這個按鈕能夠被物件和呼叫在之上的方法所訪問。

  在視區專案陣列中把這個控制元件放到我們地圖控制元件之上:

{
	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應用程式中的元件,包括Controler refs,Ext.ComponentQuery()等等。在這個例子中,為了方便,我們將使用一個元件查詢來找到在視窗中的地圖元件。一旦我們獲得了那個引用,我們可以呼叫'getMap'來獲取Leaflet地圖例項並在其上直接呼叫任何Leaflet的API函式。

  此後,你可以讓你的元件變得巧妙無比。你能為所有必需的啟動引數新增配置屬性,你就能定製每一個使用Ext Js配置引數的例項,而不是第三方庫的傳統做法。你可以新增新的屬性來切換庫特性。舉個例子,你可以新增一個屬性來啟用Leaflet的定位功能,這將會試圖呼叫你瀏覽器的地理API來查詢你的位置。你可以我的GitHub上,看到更加複雜的例子(倉庫地址

  結論

  所有的庫都不同,並可能會帶來附加的挑戰,但是這個概念將會幫助你讓你的Ext JS或者Sencha Touch應用集整合到一起。在Sencha市場和GitHub已經有很多的封裝元件可以獲得,所以你可能不需要自己建立。但是如果沒有一個你所需要的庫,你現在就知道如何建立你自己的庫並把它分享給其他Sencha社群的其他開發者。

  英文原文:Integrating Ext JS with 3rd Party Libraries

相關文章