由于JavaScript本身并不支持面向?qū)ο?,但是我們可以利用其Prototype去模擬部分面向?qū)ο蟮恼Z言特征。我們這兒要說的虛擬面向?qū)ο缶褪侵窪orado中提供的JavaScript模擬面向?qū)ο蟮木幊碳夹g(shù)。 在基礎(chǔ)教程中我們只介紹Dorado JS對(duì)象的使用和相關(guān)約定,而忽略對(duì)象的聲明、擴(kuò)展等內(nèi)容。
我們使用Dorado提供的JSDOC的時(shí)候注意到,其中Dorado的JS對(duì)象通常都包含很多的attributes,如我們?cè)L問URL:?http://dorado.bstek.com/jsdoc/
訪問dorado.widget下的Button控件:
這些attributes就是Dorado對(duì)象的虛擬屬性,之所以稱它們?yōu)樘摂M屬性是,因?yàn)樗鼈兣cJava中的屬性不同的地方在于,Java中的屬性我們都可以通過專用的getXXX/setXXX方法進(jìn)行讀取操作,但是Dorado對(duì)象的虛擬屬性我們需要通過如下的方式:
var v = editor.get("value");
button.set("caption", "OK");
也就是說當(dāng)我們看到JSDOC中某一個(gè)Dorado控件具有的某些attributes,我們就可以通過get/set方法,例如剛才我們看到的Button中有icon屬性,則我們就可以通過如下的方式設(shè)置其icon屬性:
button.set("icon", "images/button_ok.gif");
下面介紹虛擬屬性的一些其他特色: set方法支持批量屬性設(shè)置 如下代碼,我們對(duì)一個(gè)對(duì)象的多個(gè)屬性進(jìn)行賦值操作:
button.set("icon", "images/ok.gif");
button.set("caption", "OK");
button.onClick = function(){
alert("You clicked OK.");
}
這種代碼有些羅嗦,尤其在屬性較多情況下更是如此,有什么簡化的辦法呢? 虛擬屬性的set方法支持屬性批量設(shè)置,如下:
button.set({
icon: "images/ok.gif",
caption: "OK",
onClick: function() {
alert("You clicked OK.");
}
});
通過這種賦值方式可以大大的簡化代碼的書寫。 迭代式操作 通過前面的學(xué)習(xí)我們知道JSON可以構(gòu)造一個(gè)很復(fù)雜的樹結(jié)構(gòu)的對(duì)象,Dorado對(duì)象在很多情況下也是樹形結(jié)構(gòu),例如有一個(gè)oop為一個(gè)Dorado虛擬對(duì)象,其中含address虛擬屬性,而address本身又是一個(gè)Dorado虛擬屬性,我們希望取出其中的postCode,如果我們要存取postCode的值,可能的代碼有:
oop.get("address").get("postCode");
oop.get("address").set("postCode", "7232-00124");
但是利用虛擬屬性的功能,我們可以這么些代碼:
oop.get("address.postCode");
oop.set("address.postCode", "7232-00124");
這樣看起來代碼是不是簡潔多了,也很容易的就能讀懂代碼。對(duì)于迭代式get和set方法,還提供了一個(gè)更有意義的功能,即加入在迭代過程中遇到的不是一個(gè)Dorado的虛擬對(duì)象,而是一個(gè)標(biāo)準(zhǔn)的JSON對(duì)象,則這種迭代操作的處理機(jī)制依然有效。
事件 Dorado為虛擬對(duì)象增加了很多事件,這些事件與通常Dom的事件并不一樣,是Dorado為虛擬對(duì)象專門增加的事件,事件的添加方法: 方法一
button1.addListener("onClick", function(self) {
//此方法可以為一個(gè)事件添加多個(gè)監(jiān)聽函數(shù)
});
這是Dorado中內(nèi)部采用的添加事件的方法。
方法二
button1.set("onClick", function(self) {
// 此方法只能定義一個(gè)監(jiān)聽函數(shù)
});
這兒要提一下虛擬屬性的功能,前面我們介紹過虛擬屬性,通過前面的學(xué)習(xí)上述代碼的意圖就是設(shè)置button1的onClick屬性,由于不存在實(shí)際的onClick屬性,且屬性的值我們給了一個(gè)function,則Dorado事件引擎會(huì)自動(dòng)的調(diào)用button1.addListener處理機(jī)制,將這個(gè)function注冊(cè)到事件管理器中。推薦使用第二種方法,代碼更為直接,他們之間的差別在于虛擬屬性設(shè)置方法只能定義一個(gè)監(jiān)聽函數(shù),而addListener可以添加多個(gè)function。 下面說明事件的幾個(gè)公用特性,這些特性并不是每一個(gè)事件都有,但是這些特性是虛擬對(duì)象的事件的基本特性: self和arg Dorado中所有的事件都支持self和arg參數(shù),其中self表示激發(fā)事件的自身,如Button激活onClick事件,則self表示Button自身,如Editor激活onClick事件,則self表示Editor對(duì)象自身,arg的類型與具體事件類型有關(guān),很多情況下都是一個(gè)JSON對(duì)象,其中可能包含有非常豐富的傳入信息。不同的事件中arg的JSON對(duì)象的屬性是不一樣的,事件A可能arg中含有prop1,prop2,我們可以通過如下代碼獲取其屬性:
var v1 = arg.prop1;
var v2 = arg.prop2;
而事件B中可能傳入的信息就是prop3,prop4,則代碼就可能為:
var v3 = arg.prop3;
var v4 = arg.prop4;
不同事件的arg的差別,要通過JSDOC查看,例如我們看Button控件:
http://dorado.bstek.com/jsdoc/
其中的onClick事件:
注意其中arg的button,event和returnValue的說明
而其onRefreshDom事件的arg參數(shù)就為:
上面兩張截圖中onClick與onRefreshDom的事件中的arg參數(shù)是不一樣的。 this 如實(shí)做AJAX范例中,按鈕Ajax Multiply的onClick事件代碼中我們接觸到this的寫法,但是我們未細(xì)講這個(gè)this的含義:
var action = this.get("#multiplyAction");
dorado.MessageBox.prompt("Please input two numbers here", {
defaultText: "3,5",
callback: function(text) {
var nums = text.split(",");
var parameter = {
num1: nums[0],
num2: nums[1]
};
action.set("parameter", parameter).execute(function(result) {
dorado.MessageBox.alert(nums[0] + " * " + nums[1] + " = " + result);
});
}
});
其實(shí)這個(gè)this指的就是按鈕所在的視圖View:
幾乎所有事件中的this均指向的是該控件隸屬的View對(duì)象,View對(duì)象的onCreate事件中的this是指向其自身的。
onCreate事件中的this是個(gè)例外,因?yàn)榭丶偸窍缺粍?chuàng)建然后才被添加到控件樹上,因此在onCreate事件被觸發(fā)時(shí)控件并不知道其隸屬的View對(duì)象。所以onCreate事件中的this并不指向最終的View。而是指自身。
Dorado在所有的事件監(jiān)聽器中提供了一個(gè)view隱式變量指向當(dāng)前事件宿主所屬的View,此變量可以完全替代原先this的使用場景。它可以帶來以下幾個(gè)好處: 語義明確,很明顯 view.get("#dsPeople") 比 this.get("#dsPeople") 更加準(zhǔn)確的表達(dá)了代碼的含義。不用再擔(dān)心進(jìn)入閉包和回調(diào)方法之后this的指向發(fā)生變化。即使是在控件的onCreate事件中也可以使用view隱式變量。而在之前的版本中,onCreate事件里this的指向是事件宿主自身,與其他事件并不相符。邏輯返回值 所有事件的返回值類型都是邏輯型,用于通知系統(tǒng)是否繼續(xù)觸發(fā)同一事件的后續(xù)監(jiān)聽器。不返回任何值則系統(tǒng)按true來處理。 一般情況下我們并不需要關(guān)注這個(gè)邏輯返回值,但有一種特殊情況: Dorado中對(duì)象某一個(gè)事件可以定義多個(gè)Listener的時(shí)候,這些Listener會(huì)按順序依次觸發(fā),如果我們希望在第一個(gè)事件觸發(fā)的過程中,屏蔽后面Listener的觸發(fā),則我們需要在第一個(gè)Listener中明確的返回一個(gè)false。這樣后面的事件就會(huì)被跳過,不再執(zhí)行。 processDefault 很多beforeXXX事件的arg參數(shù)中都支持一個(gè)名為processDefault的可寫屬性,用于通知系統(tǒng)是否要執(zhí)行該事件所代表的后續(xù)操作。 如下的一個(gè)范例,我們對(duì)一個(gè)DataType添加一個(gè)beforeRemove的事件,并在其中判斷,如果是已婚的則不允許刪除,通過MessageBox給出提示信息,并設(shè)置arg的processDefault為false,用以告訴beforeRemove動(dòng)作如果是已婚則不執(zhí)行默認(rèn)的刪除動(dòng)作。
employeeDataType.addListener("beforeRemove", function(self, arg) {
if (arg.entity.get("married")) {
dorado.MessageBox.alert("已婚的員工不能被刪除!");
arg.processDefault = false;
}
});
拋出一個(gè)異常,同樣可以達(dá)到類似的目的。
employeeDataType.addListener("beforeRemove", function(self, arg) {
if (arg.entity.get("married")) {
throw new dorado.Exception("已婚的員工不能被刪除!");
}
});
兩種方法其實(shí)有區(qū)別,可能導(dǎo)致不同的結(jié)果!例如我們對(duì)10條員工記錄,循環(huán)做刪除動(dòng)作,例如第三條為已婚員工,則如果是用processDefault = false的處理機(jī)制,最終系統(tǒng)的效果是刪除第三條的時(shí)候給出用戶警告,但是系統(tǒng)會(huì)接著刪除第四,五條直到第十條記錄,也就是說會(huì)繼續(xù)循環(huán),最終結(jié)果是除了第三條記錄之外,其它記錄全部被刪除。但是如果采用throw new dorado.Exception()處理機(jī)制,則循環(huán)到第三條彈出異常,并終止循環(huán),后面的記錄不會(huì)不刪除。它們之間的差別,用Java關(guān)鍵字表示,就是processDefault相當(dāng)與循環(huán)體中的continue,而throw new Dorado.Exception()相當(dāng)與break。
更多建議: