基於Dojo的JavaScriptWeb用戶端介面控制項開發

來源:互聯網
上載者:User
文章目錄
  • 1.3.1 閉包
  • 1.3.2 this關鍵字
  • 1.3.3 apply函數的使用
  • 1.3.4 基於apply的dojo.hitch
  • 1.3.5 前後台互動XmlHttpRequest

 

1 前言1.1 傳統JS前台編程方式

傳統的前台編程模式如下

<HTML><br /><HEAD><br /><!—這裡引入頁面依賴的元素,包括JS 檔案<br /></HEAD><br /><BODY><br /><!—頁面HTML元素--><br /><SCRIPT><br /><!—使用者自己的指令碼代碼--><br /></SCRIPT><br /></BODY> 

可以看出,傳統的前台編程方式是面向過程的,不便於擴充於重用。在一個複雜的BS項目中,如果能夠把抽象出介面中的某些具備共性的地區,把他們的行為(包括介面元素,介面事件,以及資料)封裝起來將大大前端的開發效率。

1.2 Dojo簡介

Dojo是一個工具箱,其定義了如下三大模組

1) 各式各樣的JS標準庫方法

這些標準庫方法包羅永珍並考慮了瀏覽器安全色性以及效能,在dojo架構下建議使用這些庫函數可以屏蔽瀏覽器的差異

2) 一應俱全的Web組件包括基本組件(dijit)以及擴充(dojox)

在web組件方面,可以把Dojo的Web組件看成一個前台標籤,頁面載入完畢後dojo將會調用dojo.parser模組的parse方法掃描但前頁面中所有具備dojotype屬性的DIV標籤,把它們parse成對應的web組件。這得一提的是這些組件全部是基於物件導向的思想設計,非常便於擴充,使用者在外部可以通過重新導向基類的方法,注入自己的介面行為,或者乾脆通過繼承來重載,覆蓋父類的方法定義自己的組件。

1.3 基本概念介紹

物件導向的思想已經深入人心。而Dojo的web組件也基於物件導向的思想,所以在進一步介紹web組件之前,需要介紹一下JS的物件導向特性。

1.3.1 閉包

閉包本質上就是資料與包含資料的範圍的結合體。請看下例

function foo ()<br />{<br />var x = 10;<br />return function bar()<br />{<br /> alert(x);<br />}<br />}<br />var x = 5;<br />var barRef = foo();<br />barRef();//結果為10 

1.3.2 this關鍵字

This指的是當前代碼的調用者

例子1)

<mce:script type="text/javascript"><!--</p><p>alert(this == window);<br />// --></mce:script> 

單獨運行在頁面中的JS代碼的this指的是window對象

例子2-1)

<select id =”sel” onchange=”test();”><OPTION>1</OPTION><OPTION>2</OPTION></select><br /><mce:script type="text/javascript"><!--</p><p>function test()<br />{<br /> alert(this == document.getElementById(‘sel’));<br />}<br />// --></mce:script> 

例子2-2)

<select id =”sel” onchange=”test();”><OPTION>1</OPTION><OPTION>2</OPTION></select><br /><mce:script type="text/javascript"><!--</p><p>document.getElementById(‘sel’).onchange = test()<br />{<br /> alert(this == document.getElementById(‘sel’));<br />}<br />// --></mce:script> 

由於onchange事件可以看成select的屬性,因此可以認為是select調用了onchange,所以事件響應代碼中的this 就是該DOM節點

例子3)

<mce:script type="text/javascript"><!--</p><p>var a = {};<br />a.b = function()<br />{<br /> alert(this == a)<br />}<br />a.b();<br />// --></mce:script> 

這個例子比較明顯,由於是a調用了a.b所以在函數中。this就是a對象

1.3.3 apply函數的使用

在JavaScript中,一個函數其實是一個對象,任何一個函數都有一個apply方法,

apply方法JScript參考中的說明:應用某一對象的一個方法,用另一個對象替換當前對象。apply([thisObj[,argArray]]) 

apply([thisObj[,argArray]])中的參數為數組集合。下面來看看apply的具體應用 

// simple apply demo<br />function simpleApplyDemo(arg) {<br />window.alert(arg);<br />}<br />function handleSPA(arg) {<br />simpleApplyDemo.apply(this, arguments);<br />} 

從上面簡單的例子可以看出,apply可以把當前的參數傳遞給另外一個函數的參數中,從而調用另一個函數的應用。

apply還有一個技巧在裡面,就是用apply應用另一個函數(類)以後,當前的函數(類)就具備了另一個函數(類)的方法或者是屬性,這也可以稱之為“繼承”。看下面樣本。 

// advanced apply demo<br />function adApplyDemo(x) {<br />return ("this is never-online, BlueDestiny '" + x + "' demo");<br />}<br />function handleAdApplyDemo(obj, fname, before) {<br /> var oldFunc = obj[fname];<br /> obj[fname] = function() {<br /> return oldFunc.apply(this, before(arguments));<br /> };<br />}<br />function hellowordFunc(args) {<br /> args[0] = "hello " + args[0];<br /> return args;<br />}<br />function applyBefore() {<br />alert(adApplyDemo("world"));<br />}<br />function applyAfter() {<br />handleAdApplyDemo(this, "adApplyDemo", hellowordFunc);<br />alert(adApplyDemo("world")); // Hello world!<br />} 

1.3.4 基於apply的dojo.hitch

如果直接這麼寫obj.onclick=functiona(arguments1, arguments2){…..};

我們會發現在functiona中,this就是觸發click事件的Dom節點了

所以在我們的組件代碼中,經常出現如下代碼this.connect(obj, ‘click’, dojo.hitch(this, functiona, arguments1, arguments2));這樣functiona中的this和組件代碼中的this保持一致,也就可以訪問組件類中的屬性以及方法了

我們看一下dojo.hitch的代碼會發現如下片斷

return function(){ return scope[method].apply(scope, arguments || []); }; // Function,可見它正是利用了apply的特性實現了範圍的變更。

dojo.hitch參數表為,第一個參數為範圍,第二個參數為函數對象,從第三個參數起就是第二個參數所對應函數的參數表

1.3.5 前後台互動XmlHttpRequest

現代瀏覽器都支援XmlHttpRequest, XmlHttpRequest的調用都是非同步也就是說這樣的調用都無需頁面進行跳轉的。dojo再其上封裝了dojo.xhr類。dojo的web組件接受json(javascript object notion)資料。所以使用dojo組件無需考慮背景具體實現,只要後台能夠提供非同步請求機制,並且能夠返回Json即可。在BME R4版本中,基於structs2以及jsonlib開發了非同步請求action機制,調用這些action,BMER4版本定義了如下函數

ajax.callQueryInterface = function(url/*非同步action名稱*/,inData/*對象參數*/){<br /> var tmpData = dojo.toJson(inData); //將對象轉為Json格式字串<br /> var ret;<br /> var msg;<br /> dojo.xhrPost({//dojo封裝的xmlHttprequest方法<br /> url: url,<br /> content:{<br /> "data":tmpData<br /> },<br /> timeout: 1000,<br /> error: function() {//錯誤處理函數<br /> ret = "-1";<br /> msg=Message.getString("P405237800");<br /> },<br />load:function (response) {//處理返回<br />ret = dojo.fromJson(response);<br />。。。。。。。。。<br />。。。。。。。。。<br /> return ret;<br />}; 

2 組件開發介紹2.1 dojo.declare

dojo把與實作類別聲明和繼承有關的大量細節都封裝到一個方法中,這個方法就是dojo.declare,這個方法包括三個參數

dojo.declare(/*String*/className,//要建立的建構函式名稱

/*Function|Function[]*/superCalss,//要繼承的超類建構函式,如果是建構函式數組則是多重繼承

/*Object*/ //對象中的參數定義)

2.2 一個簡單的基於dojo開發的web組件----Hellow World

dojo.provide("bmc.widget.HelloWorld");<br />dojo.require("dijit.layout.ContentPane");<br />dojo.declare(<br /> " bmc.widget.HelloWorld",<br /> dijit.layout.ContentPane,<br /> {<br /> postCreate: function(){<br /> this.inherited(arguments);<br /> var html = 'This is a hello word widget!<BR><INPUT type = button value="alert"/>';<br /> var paneDiv = document.createElement('div');<br /> paneDiv.innerHTML = html;<br /> var button = paneDiv. getElementsByTagName('INPUT')[0]<br /> dojo.place(paneDiv, this.containerNode, 'first');<br /> this.dataForm = this.containerNode.getElementsByTagName('FORM')[0];<br /> dojo.connect(button, 'click', dojo.hitch(this, this.alertHellow));<br /> },<br /> alertHellow : function()<br /> {<br /> alert('hello');<br /> }<br />}); 

Html頁面

<div class='box' dojoType=" bmc.widget.HelloWorld"><br /></div> 

 

這個例子中使用this.connect綁定dom事件一是這個方法不會破壞原來已有的事件方法,如果button原來已有click響應函數,則這個操作將會把dojo.hitch(this, this.alertHellow)這個函數的動作追加到原來的操作後面,同時在對象銷毀的時候(頁面跳轉,重新整理),凡是被connect的函數都會去綁定,可以防止IE的記憶體泄露。

這個例子中也使用了dojo.hitch,這個方法可以改變函數的範圍,如果不使用dojo.htich則alertHellow函數中的this指向這個按鈕,如果通過dojo.hitch作用,則這個函數種的this 指向這個組件的執行個體。通過這個機制,可以完全實現組件內部介面操作的封裝。

postCreate是父類dijit.layout.ContentPane的方法,通過執行this.inherited(arguments);,父類的代碼會被執行。如果沒有這個調用,父類的方法就被覆蓋了。

2.3 HelloWord升級,支援資料傳入的表單

dojo.provide("bmc.widget.HelloWorld");<br />dojo.require("dijit.layout.ContentPane");<br />dojo.declare(<br /> " bmc.widget.HelloWorld",<br /> dijit.layout.ContentPane,<br /> {<br /> data: null,<br /> postCreate: function(){<br /> this.inherited(arguments);<br /> var html = '<FORM><INPUT name = "a" /><INPUT name = "b" /><INPUT type="button" value="test" /></FORM>';<br /> var paneDiv = document.createElement('div');<br /> paneDiv.innerHTML = html;<br /> var button = paneDiv. getElementsByTagName('INPUT')[2]<br /> dojo.place(paneDiv, this.containerNode, 'first');<br /> this.dataForm = this.containerNode.getElementsByTagName('FORM')[0];<br /> dojo.connect(button, 'click', dojo.hitch(this, this.setData));<br /> }, </p><p> setData: function()<br /> {<br /> if (this.data)<br /> {<br /> var _this = this;<br /> dojo.forEach(this.dataForm.elements, function(item)<br /> {<br /> if (!item.name)<br /> {<br /> return;<br /> }<br /> item.value = _this.data[item.name];<br /> });<br /> }<br /> }<br />}); 

Html代碼

var datatest = {};<br />datatest.a = 1;<br />datatest.b = 2;<br /><div class='box' dojoType="dijit.layout.HelloWorld" data="datatest"><br /></div> 

 

點擊test

 

這個方法中使用dojo.forEach遍曆表單元素。在function(item)

                {

 

                }

中this指向的不是組件執行個體,所以之前用一個變數_this儲存了this

2.4 總結

通過以上介紹,我們可以得出如下結論

1) Dojo是是一個純Javascript庫,後台只要提供相應的介面能夠將資料以Json的格式輸出給前台即可;

2) Dojo自身定義了完整的函數庫,屏蔽了瀏覽器的差異;

3) Dojo自身定義介面組件庫,其組件代碼採用了物件導向的思想,便於繼承以及擴充;只要組件庫豐富;

4) 當對前端介面聯動需求較為複雜的時候,基於dojo的頁面組件將是首選,因為其可以將介面中某一個具有共性的地區抽象出來,封裝這一地區的介面行為以及資料,可以用搭積木的方式完成複雜頁面的開發。

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.