摘要:網(wǎng)頁中嵌入本網(wǎng)站外提供的服務(wù),需要在網(wǎng)頁文件中插入服務(wù)引擎代碼,而其它的大量JAVASCRIPT要執(zhí)行的代碼都要在頁面解析時(shí)通過JS插件或動(dòng)態(tài)請(qǐng)求下載,要在解析器線程內(nèi)執(zhí)行屬不同域的服務(wù)代碼[1] 。自動(dòng)化代碼插入保證使用站外服務(wù)方便可靠,避免插入代碼引起網(wǎng)頁文件破壞。
關(guān)鍵詞:引擎代碼;JS插件;代碼插入;站外服務(wù)
中圖分類號(hào):TP311 文獻(xiàn)標(biāo)識(shí)碼:A 文章編號(hào):1009-3044(2014)36-8650-03
網(wǎng)頁是當(dāng)今企業(yè)的宣傳的重要窗口,現(xiàn)很多公司通過網(wǎng)頁“面對(duì)面”和客戶直接聊天,提高了業(yè)務(wù)的成功率。把本站外聊天系統(tǒng)和網(wǎng)頁融合是大多數(shù)公司的首選,特別是中小型公司。提供系統(tǒng)服務(wù)公司在保證客戶現(xiàn)有網(wǎng)頁原來功能和信息不會(huì)破壞的情況下,如何把聊天功能嵌入到客戶各網(wǎng)頁中,該文就此問題提供了一個(gè)現(xiàn)實(shí)可行的解決方案。
1 系統(tǒng)功能介紹
系統(tǒng)涉及服務(wù)提供商、請(qǐng)求服務(wù)的客戶、客戶網(wǎng)頁瀏覽者的三種角色??蛻粝蚍?wù)提供商申請(qǐng)網(wǎng)頁聊天服務(wù),首先要在服務(wù)商注冊(cè)公司服務(wù)賬號(hào),登記賬號(hào)管理員和業(yè)務(wù)咨詢?nèi)藛T,并對(duì)咨詢?nèi)藛T進(jìn)行分類記,隨后客戶可使用工具把服務(wù)商提供的網(wǎng)頁代碼插入本公司頁面。當(dāng)瀏覽者訪問客戶網(wǎng)頁時(shí)服務(wù)商嵌入客戶網(wǎng)頁的聊天請(qǐng)求界面會(huì)增強(qiáng)呈現(xiàn)在瀏覽者的面前,瀏覽者點(diǎn)擊后,客戶的工作人員就可以使用桌面聊天程序和瀏覽者(在網(wǎng)頁中)聊天,聊天的信息通過服務(wù)商傳遞到雙方。
2 插入的頁面代碼功能設(shè)計(jì)
2.1 代碼插入的工作原理
由于要執(zhí)行的代碼量比較大,在頁面中插入的代碼只是關(guān)鍵的引擎代碼,否者對(duì)原頁面維護(hù)會(huì)帶來破壞和混亂,由此需要通過JS插件方式,大量的代碼在網(wǎng)頁解析時(shí)才下載到頁面。在執(zhí)行插入的JAVASCRIPT代碼時(shí),可以生成新的DOM JS插件對(duì)象,當(dāng)瀏覽器解釋新JS插件對(duì)象時(shí)又下載執(zhí)行另一JAVASCIPT代碼。通過這種方式把所有代碼分次下載到瀏覽器中,最終聊天請(qǐng)求提示界面和的頁面無縫融合在一起顯示,成為頁面整體中的一部分。
2.2 插入的提示代碼設(shè)計(jì)
為了維護(hù)原頁面文件方便,在頁面顯示時(shí)不會(huì)影響原頁面內(nèi)容顯示的順序,減少瀏覽器執(zhí)行擦入代碼時(shí)觸發(fā)DOM的重解析,因此插入代碼的最好位置是頁面的最后面,也就是緊靠前。插入的代碼應(yīng)考慮未來服務(wù)的遷移性、客戶賬號(hào)和服務(wù)站點(diǎn)的不同性、代碼塊標(biāo)識(shí)的唯一性。插入的代碼范例如下:
<!— BEGIN{www.szyhpx.com} —> // 代碼塊標(biāo)識(shí)
//‘szyhpx是服務(wù)站點(diǎn)的標(biāo)識(shí),具體的域名在 szyhpx.js文件中定義
// 具體變量名為webAdr
// 定義網(wǎng)頁訪問軌跡函數(shù)
// 客服請(qǐng)求服務(wù)注冊(cè)名
var cmpyId='NCCDPX';
// 定義提供服務(wù)的站點(diǎn)名
var webWSId='szyhpx';
//由其它頁面進(jìn)入本頁面
var priorPage=escape(document.referrer);
var url=escape(document.URL);
var series= readCookie("series");
// 使用servlet 方式動(dòng)態(tài)生成Javascript,然后瀏覽器執(zhí)行代碼
document.write('');
<!— END{www.szyhpx.com} —>
以上代碼中服務(wù)站點(diǎn)名和具體站點(diǎn)地址(域名)的分離保證了系統(tǒng)部署的靈活性,使提供的服務(wù)可任意遷移。代碼中也定義了訪問網(wǎng)頁的軌跡,為后臺(tái)提供了分析瀏覽者的訪問行為、感興趣網(wǎng)頁的數(shù)據(jù)。
2.3 代碼引擎Servlet設(shè)計(jì)
聊天提示界面中包含了客戶業(yè)務(wù)服務(wù)部門,服務(wù)人員等有關(guān)信息,這些信息都是放在數(shù)據(jù)庫中,Servlet要把這些信息轉(zhuǎn)化成JAVASCRIPT 的變量形式,以便javascript能利用這些變量值。轉(zhuǎn)化形式有二類:一是單一變量,如生成客戶注冊(cè)號(hào)cmpId變量out.println("var cmpyId=\""+cmpyId+"\";\n");二是數(shù)組變量如定義部門變量dept并初始化String divAry=" var dept=new Array();\n"; for(int i=0;lst!=null&& i { initStr+= "dept["+ i +"]=\"" +lst.get(i).getDivisionClass() "\";\n" ; } 。 對(duì)于JAVASCRIPT函數(shù)庫文件,還是通過瀏覽器在解析時(shí)下載,因此就不用out 對(duì)象調(diào)用Print 和write的方法動(dòng)態(tài)生成,而要使瀏覽器執(zhí)行JAVSCRIPT時(shí)又觸發(fā)下載JS插件,要在JAVASCRIPT中調(diào)用DOCUMENT的write的方法。當(dāng)有多個(gè)JS插件庫下載時(shí),out.write 順序要符合JAVASCRIPT執(zhí)行代碼調(diào)用順序[2] 。在系統(tǒng)中使用了JQuery插件庫和生成界面庫displayservants.js開發(fā)庫,實(shí)現(xiàn)瀏覽器下載JS插件的代碼如下,
ws="";
out.write(" document.writeln('"+ws+"');" );
ws="";
out.write(" document.writeln('"+ws+"');" );
ws="";
out.write(" document.writeln('"+ws+"');" );
ws="";
out.write(" document.writeln('"+ws+"');" );
由于客戶網(wǎng)頁采用的字符集和JS插件不同,可在瀏覽器在下載時(shí)時(shí)要指明JS插件所用的字符集,為了保持生成的代碼字符串和JS插件代碼字符集一致,在SERVLET要使用response 對(duì)象中setCharacterEncoding 的方法設(shè)置輸出內(nèi)容的字符集(GBK),否則會(huì)導(dǎo)致界面亂碼情況。
2.4 聊天提示界面呈現(xiàn)
在生成界面時(shí)會(huì)涉及大量的字符串合并(+)操作,這種操作效率比較低,應(yīng)采用數(shù)組方式進(jìn)行字符串合并[3] .顯示提示界面的目的就是提醒瀏覽者和客戶業(yè)務(wù)人員建立會(huì)話,以及提供簡(jiǎn)約的廣告,但這界面不能影響瀏覽者的正常瀏覽。界面顯示方式一般有二種,漂浮式和彈出式,漂浮式根據(jù)瀏覽者查看網(wǎng)頁上下移動(dòng)而移動(dòng),通常在屏幕左右二側(cè)并且不宜過大;彈出式是隔一段時(shí)間顯示界面在屏幕中央,可隨時(shí)隱藏,二種界面采用層和絕對(duì)位置方式實(shí)現(xiàn)。界面顯示的絕對(duì)位置由瀏覽器二個(gè)變量決定,窗口滾動(dòng)的偏移(document.body.scrollTop/Left)和所處當(dāng)前窗口的偏移,窗口偏移位置對(duì)于漂浮式是鼠標(biāo)事件的坐標(biāo)(event.clientX/Y),彈出式是根據(jù)界面窗口和瀏覽器窗口大小算出。浮漂式瀏覽者可直接選擇具體的業(yè)務(wù)人員聊天,而彈出式則是想根據(jù)瀏覽者選擇的業(yè)務(wù)部門,然后由系統(tǒng)根據(jù)某種原則指派一位業(yè)務(wù)人員。漂浮式要顯示客戶業(yè)務(wù)部門和所屬部門的業(yè)務(wù)人員,在建立界面時(shí)采用多層次表格方式,如要顯示的部門和人員比較多時(shí)不適合采用此界面,而應(yīng)采用彈出式界面。二種界面的示意圖如下,左圖為漂浮式右圖為彈出式。
圖1 聊天提示界面
在漂浮是提示界面中,需要顯示業(yè)務(wù)人員的在線狀態(tài),并要不斷刷新。在線狀態(tài)數(shù)據(jù)和網(wǎng)頁通常不在同一域,這就涉及了跨域異步安全訪問問題,直接在瀏覽器Timer中不能訪問不同域。為了減少?gòu)?fù)雜性在漂浮式界面中只顯示在線的”初始“狀態(tài),由瀏覽者操作刷新在線狀態(tài),刷新單個(gè)或所有?;跇I(yè)務(wù)聊天的特殊性,在線狀態(tài)在瀏覽網(wǎng)頁期間改變的概率比較低,即使有改變?yōu)g覽者在請(qǐng)求聊天時(shí)也能知道這種改變,對(duì)業(yè)務(wù)來說沒有影響。
相對(duì)漂浮式彈出式能顯示更多的內(nèi)容,適合于做額外的宣傳廣告,廣告內(nèi)容可在后臺(tái)編輯修改,此外還可顯示瀏覽者訪問網(wǎng)頁的地點(diǎn)。
3 代碼插入自動(dòng)化
市場(chǎng)上有些類似的產(chǎn)品,插入引擎代碼還是手工,客戶注冊(cè)賬號(hào)后服務(wù)商把要插入的代碼(含注冊(cè)信息)交給客戶,由客戶手動(dòng)把代碼插入到網(wǎng)頁中,當(dāng)網(wǎng)頁比較多時(shí)非常繁瑣。通過后臺(tái)管理網(wǎng)站的FTP服務(wù)器可進(jìn)行自動(dòng)插入,避免手工插入對(duì)網(wǎng)頁的破壞。自動(dòng)插入的流程圖如下:
圖2 代碼插入流程
3.1 代碼塊插入和刪除
針對(duì)不同的網(wǎng)頁格式按從后查找的方式找出網(wǎng)頁最后的標(biāo)簽[4],然后查找代碼塊的結(jié)束標(biāo)簽<!— END{www.szyhpx.com} —>和開始標(biāo)簽<!— BEGIN{www.szyhpx.com}—>,如果標(biāo)簽存在則要?jiǎng)h除在網(wǎng)頁的整個(gè)代碼塊,如代碼塊標(biāo)志破壞則用日志形式記錄網(wǎng)頁名稱。由于網(wǎng)頁內(nèi)容比較多,如搜索整個(gè)網(wǎng)頁效率比較低,規(guī)定范圍從網(wǎng)頁結(jié)束簽向前1.5/2倍的代碼塊大小。由于代碼塊中包含具體客戶的個(gè)體信息,在通用代碼塊中設(shè)置了這些信息占位符,上傳之前要替換占位符。插入刪除規(guī)則說明如下:
1) WebPageYhJavScriptLoc 類中包含以上三個(gè)標(biāo)簽的在網(wǎng)頁中位置,其值由下面方法求出。 WebPageYhJavScriptLoc insertYhCodeLoc=ComareArray. webPageFromLastFindArray(txtcont,begTag,endTag,webPageEndTag)。
2) 判斷三個(gè)標(biāo)簽位置的合法性 insertYhCodeLoc.yhJavaScriptEndLoc>0 && insertYhCodeLoc.yhJavaScriptBegLoc==-1 為非法,拋出異常。
insertYhCodeLoc.yhJavaScriptEndLoc==-1 && insertYhCodeLoc.yhJavaScriptBegLoc〉0 合法但insertYhCodeLoc.yhJavaScriptEndLoc會(huì)轉(zhuǎn)化成標(biāo)簽位置。
刪除二標(biāo)簽位置之間的代碼塊。
3) insertYhCodeLoc.yhJavaScriptBegLoc==-1 && insertYhCodeLoc.yhJavaScriptEndLoc==-1在標(biāo)簽位置處直接插入代碼。
3.2 網(wǎng)站的目錄映射
把網(wǎng)站的目錄結(jié)構(gòu)映射到樹形界面中,建立多層樹形結(jié)構(gòu),客戶根據(jù)樹形目錄選擇要插入代碼網(wǎng)頁所在的目錄,或者排除的不要修改的目錄。代碼中NamedVector 類中繼承Vector系統(tǒng)類,包含父目錄串,用于存放多個(gè)子目錄。下面函數(shù)執(zhí)行完成后,所有的目錄按樹形結(jié)構(gòu)保存到第一次調(diào)用begVc對(duì)象中,代碼范例如下。
public void createTreeModule( NamedVector begVc,String abPath) throws Exception
{
NamedVector subVc=null;
if(isIncludePath(abPath)) return;
// ftp獲取本目錄下的所有子目錄
Vector
if(dirs==null || dirs.size()==0) return ;
for(int i=0;i { subVc=new NamedVector(dirs.get(i)); // 儲(chǔ)存子目錄 begVc.addSubVector(subVc); // 根目錄特殊性 subVc.abPath=( abPath.equals("/") ? abPath+dirs.get(i):abPath+"/"+dirs.get(i) ); createTreeModule(subVc,subVc.abPath); }} 3.3 上傳文件完整性的保證 在上傳網(wǎng)頁文件過程中,如果文件上傳突然中斷,將會(huì)導(dǎo)致網(wǎng)頁內(nèi)容的破壞,造成網(wǎng)頁不能正常顯示。網(wǎng)頁文件下載到內(nèi)存并插入代碼完成后,在下載目錄中建立類型和網(wǎng)頁文件一致的臨時(shí)備份文件,文件名稱是系統(tǒng)生成的唯一的ID,在XML文件中登記這二個(gè)備份的文件,同時(shí)記錄網(wǎng)頁在FTP服務(wù)器中的目錄。上傳成功后刪除所有這些信息,失敗后要把備份文件重新上傳(REDO/UNDO)。XML格式定義范例如下: 4 結(jié)束語 本文涉及實(shí)現(xiàn)的功能只是對(duì)傳統(tǒng)聊天系統(tǒng)的擴(kuò)展,即通過網(wǎng)頁插件的形式把普通網(wǎng)頁和聊天系統(tǒng)連接到一起,騰訊QQ就是一個(gè)實(shí)例,通過在網(wǎng)頁中點(diǎn)擊QQ聊天提醒進(jìn)入瀏覽者桌面QQ聊天程序,雙方都用QQ賬號(hào)連接,這種方式缺陷是引起QQ號(hào)泄露,擴(kuò)充其它管理功能受到限制。 把瀏覽者瀏覽網(wǎng)頁過程和聊天產(chǎn)生數(shù)據(jù)管理起來并對(duì)之分析利用,這樣一些原始數(shù)據(jù)收集也需要在網(wǎng)頁中插入相關(guān)代碼,并在后臺(tái)建立業(yè)務(wù)數(shù)據(jù)管理,這些功能設(shè)計(jì)實(shí)現(xiàn)超出本文所討論的范圍。 參考文獻(xiàn): [1] Christophe Porteneuve. Javascript 修煉之道[M]. 鞏朋, 張鐵,譯.北京:人民郵電出版社,2011:70. [2] Nicholas C Zakas.Javascript高級(jí)程序設(shè)計(jì)[M].北京:人民郵電出版社,2012:12. [3] Den Odell.Javascript RIA 開發(fā)實(shí)踐[M].北京:清華大學(xué)出版社,2010:146. [4] Den Odell.Javascript RIA 開發(fā)實(shí)踐[M].北京:清華大學(xué)出版社,2010:125.
2) 判斷三個(gè)標(biāo)簽位置的合法性 insertYhCodeLoc.yhJavaScriptEndLoc>0 && insertYhCodeLoc.yhJavaScriptBegLoc==-1 為非法,拋出異常。
insertYhCodeLoc.yhJavaScriptEndLoc==-1 && insertYhCodeLoc.yhJavaScriptBegLoc〉0 合法但insertYhCodeLoc.yhJavaScriptEndLoc會(huì)轉(zhuǎn)化成標(biāo)簽位置。
刪除二標(biāo)簽位置之間的代碼塊。
3) insertYhCodeLoc.yhJavaScriptBegLoc==-1 && insertYhCodeLoc.yhJavaScriptEndLoc==-1在標(biāo)簽位置處直接插入代碼。
3.2 網(wǎng)站的目錄映射
把網(wǎng)站的目錄結(jié)構(gòu)映射到樹形界面中,建立多層樹形結(jié)構(gòu),客戶根據(jù)樹形目錄選擇要插入代碼網(wǎng)頁所在的目錄,或者排除的不要修改的目錄。代碼中NamedVector 類中繼承Vector系統(tǒng)類,包含父目錄串,用于存放多個(gè)子目錄。下面函數(shù)執(zhí)行完成后,所有的目錄按樹形結(jié)構(gòu)保存到第一次調(diào)用begVc對(duì)象中,代碼范例如下。
public void createTreeModule( NamedVector begVc,String abPath) throws Exception
{
NamedVector subVc=null;
if(isIncludePath(abPath)) return;
// ftp獲取本目錄下的所有子目錄
Vector
if(dirs==null || dirs.size()==0) return ;
for(int i=0;i { subVc=new NamedVector(dirs.get(i)); // 儲(chǔ)存子目錄 begVc.addSubVector(subVc); // 根目錄特殊性 subVc.abPath=( abPath.equals("/") ? abPath+dirs.get(i):abPath+"/"+dirs.get(i) ); createTreeModule(subVc,subVc.abPath); }} 3.3 上傳文件完整性的保證 在上傳網(wǎng)頁文件過程中,如果文件上傳突然中斷,將會(huì)導(dǎo)致網(wǎng)頁內(nèi)容的破壞,造成網(wǎng)頁不能正常顯示。網(wǎng)頁文件下載到內(nèi)存并插入代碼完成后,在下載目錄中建立類型和網(wǎng)頁文件一致的臨時(shí)備份文件,文件名稱是系統(tǒng)生成的唯一的ID,在XML文件中登記這二個(gè)備份的文件,同時(shí)記錄網(wǎng)頁在FTP服務(wù)器中的目錄。上傳成功后刪除所有這些信息,失敗后要把備份文件重新上傳(REDO/UNDO)。XML格式定義范例如下: 4 結(jié)束語 本文涉及實(shí)現(xiàn)的功能只是對(duì)傳統(tǒng)聊天系統(tǒng)的擴(kuò)展,即通過網(wǎng)頁插件的形式把普通網(wǎng)頁和聊天系統(tǒng)連接到一起,騰訊QQ就是一個(gè)實(shí)例,通過在網(wǎng)頁中點(diǎn)擊QQ聊天提醒進(jìn)入瀏覽者桌面QQ聊天程序,雙方都用QQ賬號(hào)連接,這種方式缺陷是引起QQ號(hào)泄露,擴(kuò)充其它管理功能受到限制。 把瀏覽者瀏覽網(wǎng)頁過程和聊天產(chǎn)生數(shù)據(jù)管理起來并對(duì)之分析利用,這樣一些原始數(shù)據(jù)收集也需要在網(wǎng)頁中插入相關(guān)代碼,并在后臺(tái)建立業(yè)務(wù)數(shù)據(jù)管理,這些功能設(shè)計(jì)實(shí)現(xiàn)超出本文所討論的范圍。 參考文獻(xiàn): [1] Christophe Porteneuve. Javascript 修煉之道[M]. 鞏朋, 張鐵,譯.北京:人民郵電出版社,2011:70. [2] Nicholas C Zakas.Javascript高級(jí)程序設(shè)計(jì)[M].北京:人民郵電出版社,2012:12. [3] Den Odell.Javascript RIA 開發(fā)實(shí)踐[M].北京:清華大學(xué)出版社,2010:146. [4] Den Odell.Javascript RIA 開發(fā)實(shí)踐[M].北京:清華大學(xué)出版社,2010:125.
2) 判斷三個(gè)標(biāo)簽位置的合法性 insertYhCodeLoc.yhJavaScriptEndLoc>0 && insertYhCodeLoc.yhJavaScriptBegLoc==-1 為非法,拋出異常。
insertYhCodeLoc.yhJavaScriptEndLoc==-1 && insertYhCodeLoc.yhJavaScriptBegLoc〉0 合法但insertYhCodeLoc.yhJavaScriptEndLoc會(huì)轉(zhuǎn)化成標(biāo)簽位置。
刪除二標(biāo)簽位置之間的代碼塊。
3) insertYhCodeLoc.yhJavaScriptBegLoc==-1 && insertYhCodeLoc.yhJavaScriptEndLoc==-1在標(biāo)簽位置處直接插入代碼。
3.2 網(wǎng)站的目錄映射
把網(wǎng)站的目錄結(jié)構(gòu)映射到樹形界面中,建立多層樹形結(jié)構(gòu),客戶根據(jù)樹形目錄選擇要插入代碼網(wǎng)頁所在的目錄,或者排除的不要修改的目錄。代碼中NamedVector 類中繼承Vector系統(tǒng)類,包含父目錄串,用于存放多個(gè)子目錄。下面函數(shù)執(zhí)行完成后,所有的目錄按樹形結(jié)構(gòu)保存到第一次調(diào)用begVc對(duì)象中,代碼范例如下。
public void createTreeModule( NamedVector begVc,String abPath) throws Exception
{
NamedVector subVc=null;
if(isIncludePath(abPath)) return;
// ftp獲取本目錄下的所有子目錄
Vector
if(dirs==null || dirs.size()==0) return ;
for(int i=0;i { subVc=new NamedVector(dirs.get(i)); // 儲(chǔ)存子目錄 begVc.addSubVector(subVc); // 根目錄特殊性 subVc.abPath=( abPath.equals("/") ? abPath+dirs.get(i):abPath+"/"+dirs.get(i) ); createTreeModule(subVc,subVc.abPath); }} 3.3 上傳文件完整性的保證 在上傳網(wǎng)頁文件過程中,如果文件上傳突然中斷,將會(huì)導(dǎo)致網(wǎng)頁內(nèi)容的破壞,造成網(wǎng)頁不能正常顯示。網(wǎng)頁文件下載到內(nèi)存并插入代碼完成后,在下載目錄中建立類型和網(wǎng)頁文件一致的臨時(shí)備份文件,文件名稱是系統(tǒng)生成的唯一的ID,在XML文件中登記這二個(gè)備份的文件,同時(shí)記錄網(wǎng)頁在FTP服務(wù)器中的目錄。上傳成功后刪除所有這些信息,失敗后要把備份文件重新上傳(REDO/UNDO)。XML格式定義范例如下: 4 結(jié)束語 本文涉及實(shí)現(xiàn)的功能只是對(duì)傳統(tǒng)聊天系統(tǒng)的擴(kuò)展,即通過網(wǎng)頁插件的形式把普通網(wǎng)頁和聊天系統(tǒng)連接到一起,騰訊QQ就是一個(gè)實(shí)例,通過在網(wǎng)頁中點(diǎn)擊QQ聊天提醒進(jìn)入瀏覽者桌面QQ聊天程序,雙方都用QQ賬號(hào)連接,這種方式缺陷是引起QQ號(hào)泄露,擴(kuò)充其它管理功能受到限制。 把瀏覽者瀏覽網(wǎng)頁過程和聊天產(chǎn)生數(shù)據(jù)管理起來并對(duì)之分析利用,這樣一些原始數(shù)據(jù)收集也需要在網(wǎng)頁中插入相關(guān)代碼,并在后臺(tái)建立業(yè)務(wù)數(shù)據(jù)管理,這些功能設(shè)計(jì)實(shí)現(xiàn)超出本文所討論的范圍。 參考文獻(xiàn): [1] Christophe Porteneuve. Javascript 修煉之道[M]. 鞏朋, 張鐵,譯.北京:人民郵電出版社,2011:70. [2] Nicholas C Zakas.Javascript高級(jí)程序設(shè)計(jì)[M].北京:人民郵電出版社,2012:12. [3] Den Odell.Javascript RIA 開發(fā)實(shí)踐[M].北京:清華大學(xué)出版社,2010:146. [4] Den Odell.Javascript RIA 開發(fā)實(shí)踐[M].北京:清華大學(xué)出版社,2010:125.