DOM事件標準定義了兩種事件流,這兩種事件流有著顯著的不同并且可能對你的應用有著相當大的影響。這兩種事件流分別是捕獲和冒泡。和許多Web技術一樣,在它們成為標準之前,Netscape和微軟各自不同地實現了它們。Netscape選擇實現了捕獲事件流,微軟則實現了冒泡事件流。幸運的是,W3C決定組合使用這兩種方法,并且大多數新瀏覽器都遵循這兩種事件流方式。
默認情況下,事件使用冒泡事件流,不使用捕獲事件流。然而,在Firefox和Safari里,你可以顯式的指定使用捕獲事件流,方法是在注冊事件時傳入useCapture參數,將這個參數設為true。下面用個例子分別來測試這兩種事件流。
1、冒泡事件流
當事件在某一DOM元素被觸發時,例如用戶在客戶名字節點上點擊鼠標,事件將跟隨著該節點繼承自的各個父節點冒泡穿過整個的DOM節點層次,直到它遇到依附有該事件類型處理器的節點,此時,該事件是onclick事件。在冒泡過程中的任何時候都可以終止事件的冒泡,在遵從W3C標準的瀏覽器里可以通過調用事件對象上的stopPropagation()方法,在Internet Explorer里可以通過設置事件對象的cancelBubble屬性為true。如果不停止事件的傳播,事件將一直通過DOM冒泡直至到達文檔根。
測試的HTML文件,其中用到了mootools-release-1.11.js,對mootools的代碼進行了改動:
addListener: function(type, fn,setCapture){
if (this.addEventListener) this.addEventListener(type, fn, setCapture);
else {
this.attachEvent('on' + type, fn);
if (setCapture) this.setCapture(true);
}
return this;
}
if (this.addEventListener) this.addEventListener(type, fn, setCapture);
else {
this.attachEvent('on' + type, fn);
if (setCapture) this.setCapture(true);
}
return this;
}
給addListener方法里增加了setCapture參數,用于測試捕獲事件流。
<body>
<div id="dd1-ct" style="width:400px;height:400px;border:1px solid #999;padding:2px">Container
<div id="dd1-item1" style="width:200px;height:200px;border:1px solid #999;padding:2px">Item1
<div id="dd1-item2" style="width:100px;height:100px;border:1px solid #999;padding:2px">Item2</div>
</div>
</div>
<div id='rh'></div>
</body>
<div id="dd1-ct" style="width:400px;height:400px;border:1px solid #999;padding:2px">Container
<div id="dd1-item1" style="width:200px;height:200px;border:1px solid #999;padding:2px">Item1
<div id="dd1-item2" style="width:100px;height:100px;border:1px solid #999;padding:2px">Item2</div>
</div>
</div>
<div id='rh'></div>
</body>
效果:

js:
fn1=function(e){
// e.stopPropagation();
$('rh').innerHTML+='Item1 clicked!******';
};
fn2=function(e){
// e.stopPropagation();
$('rh').innerHTML+='Item2 clicked!-------';
};
fn=function(e){
// e.stopPropagation();
$('rh').innerHTML+='Container clicked!&&&&&&&&';
};
$('dd1-item2').addListener('click', fn2.bindWithEvent(),false);
$('dd1-item1').addListener('click', fn1.bindWithEvent(),false);
$('dd1-ct').addListener('click', fn.bindWithEvent(),false);
// e.stopPropagation();
$('rh').innerHTML+='Item1 clicked!******';
};
fn2=function(e){
// e.stopPropagation();
$('rh').innerHTML+='Item2 clicked!-------';
};
fn=function(e){
// e.stopPropagation();
$('rh').innerHTML+='Container clicked!&&&&&&&&';
};
$('dd1-item2').addListener('click', fn2.bindWithEvent(),false);
$('dd1-item1').addListener('click', fn1.bindWithEvent(),false);
$('dd1-ct').addListener('click', fn.bindWithEvent(),false);
測試結果ie和ff下效果一致:單擊item2,會依次觸發fn2、fn1、fn;單擊item1,會依次觸發fn1、fn;單擊Container,只會觸發fn;當在任何一個事件處理器里調用e.stopPropagation();都會阻止事件的冒泡。
2、捕獲事件流
事件的處理將從DOM層次的根開始,而不是從觸發事件的目標元素開始,事件被從目標元素的所有祖先元素依次往下傳遞。在這個過程中,事件會被從文檔根到事件目標元素之間各個繼承派生的元素所捕獲,如果事件監聽器在被注冊時設置了useCapture屬性為true,那么它們可以被分派給這期間的任何元素以對事件做出處理;否則,事件會被接著傳遞給派生元素路徑上的下一元素,直至目標元素。事件到達目標元素后,它會接著通過DOM節點再進行冒泡。
這里ie與ff存在著很大的差異,甚至ie6與ie7的表現也各不相同,所以分開測試。
a、ff
事件從從DOM層次的根開始往下傳遞時,會被useCapture屬性為true的事件監聽器所捕獲,而到達目標元素再從目標元素冒泡時,則會被useCapture屬性為false的事件監聽器所捕獲。當在任何一個事件處理器里調用e.stopPropagation();都會阻止事件的傳播。
b、ie6
用事實說話:
第一種情況:
$('dd1-item2').addListener('click', fn2.bindWithEvent(),true);
$('dd1-item1').addListener('click', fn1.bindWithEvent(),true);
$('dd1-ct').addListener('click', fn.bindWithEvent(),true);
$('dd1-item1').addListener('click', fn1.bindWithEvent(),true);
$('dd1-ct').addListener('click', fn.bindWithEvent(),true);
單擊瀏覽器的任何位置,都只是觸發fn;
第二種情況:
$('dd1-item2').addListener('click', fn2.bindWithEvent(),true);
$('dd1-item1').addListener('click', fn1.bindWithEvent(),true);
$('dd1-ct').addListener('click', fn.bindWithEvent(),false);
$('dd1-item1').addListener('click', fn1.bindWithEvent(),true);
$('dd1-ct').addListener('click', fn.bindWithEvent(),false);
單擊瀏覽器的任何位置,會依次觸發fn1、fn;
第三種情況:
$('dd1-item2').addListener('click', fn2.bindWithEvent(),true);
$('dd1-item1').addListener('click', fn1.bindWithEvent(),false);
$('dd1-ct').addListener('click', fn.bindWithEvent(),false);
$('dd1-item1').addListener('click', fn1.bindWithEvent(),false);
$('dd1-ct').addListener('click', fn.bindWithEvent(),false);
單擊瀏覽器的任何位置,會依次觸發fn2、fn1、fn;
結論:如果HTML元素捕獲了通過該元素的setCapture()方法對這個元素的設置,依附于該元素的處理器將會被事件觸發,即使setCapture()方法
被調用的這個元素不在目標元素的祖先路徑中。事實上你甚至單擊瀏覽器的非頁面部分都會觸發事件處理器。并且事件一旦被捕獲就不會繼續再
往下傳播(即使該元素在目標元素的祖先路徑中),而是立刻冒泡。e.stopPropagation();會阻止事件的冒泡。
c、ie7
測試效果與冒泡事件流一致。將對捕獲事件流的支持干掉了?
結論:正如mootools所做的,避免捕獲事件流。
工作流現在已經應用的非常廣泛了,審批OA等等自然不必多說,許多業務系統里也有大量的應用。前兩天的
一個項目就是使用工作流將整個項目管理的過程進行整合,包括了前期預算、項目進度管理、合同管理等等。
可供選擇的工作流也很多,商業的、開源的。那么你是如何評價一個工作流產品的好壞的呢?你的標準是什么?
當然,用戶也經常會問我這個問題,我的回答是:根據你實際的業務。是的,不管是什么樣的工作流,都是
為了滿足業務的需要,你把你的需求提出來,我們看看是否滿足,不能直接滿足,最合適的間接方式又是什么。你說,我要有催辦。是的,我們有。你說,我要有任意回退和任意流。是的,我們有。你說,我想對流程實例進行分級管理。oh,沒有也,重要嗎?讓我們想想其他辦法。你說,你們符合BPEL標準嗎?這個。。。你說,你們采用了petri網模型嗎?汗。。。你說,你們是SOA架構嗎?。。。
我的衡量標準是這樣的:
1、流轉功能
包括了基本的工作流模式實現,串行、并發、分支、匯聚、循環等等。這個是最基本的。其實打開流程設計器拖拖拽拽很快就能知道這個產品到底實現了哪些流轉模型。實際這個的實現也是引擎的核心。有多種模型可以選擇。petri 模型應該是最靈活的了,也有很大的實現難度。但是流程模型做這么靈活,到底實際能用上多少……就我個人的經驗來說,大部分的復雜性都是由流程的分支并發(m/n)引起的,最壞的辦法是強制要求客戶將這些并發的任務改成 step by step 的執行。這樣犧牲一點效率,還是可以把項目做成的。
2、業務的內在支持
比如說催辦、時間服務、收回等等。我覺得這個與實際業務掛鉤,反而是最為主要的考慮。因為采用間接的方式必然會產生編程,而很顯然會耗費成本。
3、與業務的契合方式
流程維護流轉。業務還是自己實現。如何將這兩者很好的銜接起來。同時這個過程還存在權限的限定,每個運行節點對業務的權限肯定存在差別,是否有一套完整的解決方案?當然這其中也包括了組織機構的適配,對各種組織模型的支持。
4、定義良好的API
通常會存在工作流無法直接滿足的業務場景,那么肯定需要程序直接調用工作流的API,清晰且簡潔的API。
5、流程的仿真
這種仿真比較簡單,目的在于檢驗所定義的流程是否正確。出錯要有明確的提示信息。普元的單點調試?
6、電子表單
我始終覺得電子表單目前實際應用并不理想,它僅僅只能處理簡單的業務。但是銷售的經驗告訴我,這是一個巨大的閃光點。用戶喜歡自己動手。流程定義實際最終用戶很難實際操作。我在想:簡化版本的流程設計器+電子表單也許會有很好的售前效果。
7、良好的售后
8、良好的最終用戶體驗
9、性能
10、最好能夠和標準扯上關系,可是誰知道我是否真的有關系呢?
這是一個完全基于js的應用程序,區別于一般的web應用,它是oaop。大概需要一些什么樣的工作呢?
大概的概念:
1、容器
是的,需要容器。容器的兩個目的:布局和管理組件。組件之間的相互通信以及影響都需要容器來協調。管理組件之間的狀態,組件需要向容器進行注冊。對組件傳播過來的事件,容器需要做出處理,調用相關其他組件的方法或者忽略或者繼續向上一級容器傳播。
2、組件
組件的目的是完全屏蔽對dom編程的依賴,同時屏蔽底層的瀏覽器事件,例如鼠標單擊、雙擊等等,對這些事件進行完全的封裝。組件有著自己的生命周期:初始化、渲染、重畫、銷毀等等。由組件完成頁面的渲染工作,例如節點、畫板、連線等等。
3、模型
在頁面進行建模是必要的,例如活動節點、流程等等,這些模型與組件銜接,它們之間的狀態互相影響,比如節點組件名稱的改變實際影響的是所對于節點模型的屬性。畫板節點的增加實際也會給響應的流程定義模型新增一個活動節點。
4、與服務器交互
與服務器的交互完全基于xml。流程定義模型有著自己的xml方法,由xml解析為模型,由模型解析為xml,雙向的過程。本地存儲。很自然的選擇。
可能的難點:
最大的難點就是組件的實現,事件的處理以及傳播機制。
開發的過程:
1、底層庫的選擇
面向對象的開發方式,底層庫需要完成的工作:繼承、接口實現、事件的統一處理接口、element DOM編程的封裝。
2、基本組件的開發
畫板、圖形組件、連線組件、彈出面板、簡單表格組件、樹等等。封裝基本的事件??梢远ㄖ剖录?br />
3、容器的開發,管理組件
組件實際也是容器的實現,比如畫板的概念。畫板中節點之間的互相影響。
4、加入模型的支持
5、xml與模型之間的js解析
參考:
ext是一個不錯的參考,但是太笨重,功能越多越緩慢,輕量實現。主要參考其中容器以及組件的概念。
draw2d 實現太簡單,基本就是一個圖形庫,考慮其中對圖形組件的實現。
內容
序
致謝
關于作者
第1章 AJAX和富互聯網應用
轉變中的Web傳統Web應用的痛處
AJAX止痛藥
企業中的AJAX
采用AJAX的驅動因素
可用性
網絡利用率
以數據為中心
遞增的技巧、工具和技術升級
服務器不可知論
關于應用
AJAX技術
編程模式
AJAX的替換技術
XUL
XAML
Java Applets 和Web Start
Adobe Flash,Flex和Apollo
OpenLaszlo
小結
資源
第2章 AJAX組成技術(AJAX Building block)
JavaScriptJavaScript類型
閉包
面向對象的JavaScript
Prototype屬性
面向對象編程(OOP)和繼承(Inheritance)
易變性(Mutability)
線程(Threading)
錯誤處理(Error Handling)
命名空間(Namespacing)
文檔對象模型(Document Object Model)
基本原理
操作DOM
層疊樣式表
繼承和層疊(Inheritance and the Cascade)
內聯樣式
樣式表
動態樣式
事件
事件流
事件綁定
跨瀏覽器事件
事件對象
客戶端通信(Client-Side Messageing)
XMLHttpRequest基礎
處理數據
小結
資源
第3章 Web瀏覽器中的AJAX
增量的AJAX對服務器影響
HTML標準
文檔類型定義(Document Type Definitions)
盒子模型
啟動加載AJAX組件
onload事件
瀏覽器編碼技巧
模型-視圖-控制器
視圖
控制器
模型
AJAX MVC
AJAX模型
AJAX視圖
AJAX控制器
面向方面的JavaScript
小結
資源
第4章 AJAX組件
命令式組件聲明式組件
服務器端聲明式編程
聲明式Google地圖
替代方法
自定義聲明式組件
行為式組件
聲明式組件
關于聲明
構建組件
基本功能
連接到服務器
最終版本
小結
資源
第5章 從設計到部署
設計為AJAX建模
應用模型-視圖-控制器模式
優先考慮性能問題
設計原型
線框繪制
驗證設計決議
測試
測試驅動開發
調試
部署
JavaScript壓縮
圖片合并
保護知識產權
文檔
小結
資源
第6章 AJAX架構
多層架構:從單層到多層異步消息
輪詢
服務器推送
Comet
跟蹤請求
緩存:處理數據
基本緩存
在組件中緩存
在瀏覽器中緩存
在服務器中緩存
在數據庫中緩存
MySQL
MS SQL Server
Oracle
更新服務器端模型:并發
悲觀鎖定
只讀鎖定
樂觀鎖定
沖突鑒定
沖突解決
自動化的沖突解決
流量控制(Throttling)
客戶端
服務端
可伸縮性
負載平衡和群集
AJAX可伸縮性問題
離線AJAX
Firefox離線存儲
Internet Explorer userData離線存儲
使用Flash客戶端存儲
離線AJAX和并發
小結
資源
第7章 Web服務和安全性
Web服務Web服務協議
表象狀態傳輸
XML遠程過程調用
Web服務
選擇合適的工具
客戶端的SOAP
IBM Web服務JavaScript庫
Firefox
Internet Explorer
跨域Web服務
服務器代理
URL片段標識符
Flash跨域XML
腳本注入
安全性
AJAX的安全性考慮
跨域漏洞
跨站腳本
跨站偽造請求
JavaScipt劫持
SQL注入
預處理語句
存儲過程
XPath注入
數據加密和隱私
防火墻
小結
資源
第8章 AJAX可用性
常見問題
后退按鈕和書簽
頁面大小
自動提交
可訪問性
識別用戶的可訪問性需求
JavaScript和Web可訪問性
屏幕閱讀器和可訪問性
兼容JAWS的AJAX交互
鍵盤可訪問性
可用性測試
迅速而又隨性的測試
招募參與者
設計和運行測試
軟件斷言測試
用于測試可用性的工具
對軟件輔助測試的一般忠告
小結
資源
第9章 用戶界面模式
顯示模式動畫模式
交互模式
基本交互模式
小結
資源
拖拽資源
進度欄資源
活動指示器資源
顏色淡出資源
即時編輯資源
向下鉆取資源
即時搜索資源
即時表單資源
第10章 風險和最佳實踐
風險來源
技術風險
文化和政治風險
市場風險
技術風險
范圍
瀏覽器能力
可維護性
向前兼容
第三工具支持和代碼過時
文化和政治風險
終端用戶的期待
可培訓性
合法性
市場風險
搜索引擎的可訪問性
范圍
貨幣化
風險評估和最佳實踐
采用特定的AJAX框架或者組件
漸進增強和不唐突的JavaScript
Google 網站地圖
可視化的提示
避免鍍金式設計
采用一種收益模型
把培訓作為應用的一部分
小結
資源
搜索引擎優化
統計
網站地圖
屏幕截取工具
第11章 案例研究
基于Web2.0 重新武裝美國國防部背景
挑戰
解決方案
采用技術
成果
Agrium公司整合AJAX技術到業務
背景
挑戰
解決方案
采用技術
成果
AJAX助力國際運輸和物流公司
背景
挑戰
解決方案
采用技術
成果
小結
資源
附錄A OpenAjax Hub
主要特性:發布/注冊管理器范例
未來對OpernAjax Hub支持的工具包
索引
時間真快,一晃08年都過了半個月。一直很忙,也不知道在忙些什么東西。領導催著要份年終總結,于是就有了這個東西。還是分成兩個部分:工作和生活。工作:
1、年初的時候繼續業務平臺的開發,主要是修改BUG和書寫使用文檔,公司開始增加測試的崗位,平臺也開始有訂單,于是BUG像雨后春筍般的茁壯成長出來。實際一直到現在,那份長長的BUG單依舊存在,改不完的BUG?,F在有很深的體會:一個好的產品,并不在于采用了多么先進的技術,重要的是要成熟,要貼近業務,而這需要的是時間和大量的項目經驗。所以,要是想節約成本采購一個業務平臺,首先需要考慮的是這個平臺存在幾年了?都被哪些實際項目采用過?它面對的業務是什么,是否符合我項目大部分的需求?對于號稱采用很多新技術和通用性非常強且剛開發出來的所謂平臺一定要慎用,很可能你就成了實驗品。
2、業務平臺的價值。其實業務平臺是有很大的存在價值的。這個價值就是業務。我們公司產品的口號是:釋放你的技術,專注你的業務。我認為這個口號相當不妥,正確的應該是:發揮你的技術,我們替你思考業務。業務平臺還有生存的意義,至于意義單一的所謂開發平臺,我看還是洗洗睡吧。
3、5月份開始進入工作流的開發,一直到現在。對工作流有了很多新的認識。工作流應該算是公司最核心的產品了。代碼很臃腫,沒有測試,但是分層還是非常的清晰。期間開始增加測試并增加功能,對引擎部分做了部分的重構。中間也陸續做過工作流的售前和售后工作。工作流,感覺是越來越普及了。但是感覺市場卻沒有想象的那么好,單獨的工作流引擎有沒有前景?其實可以這樣分析:很多行業都有他們自己針對的行業軟件公司,這些公司都有自己的業務平臺和流程組件,雖然不是獨立對外賣的;另外就是中小型企業和客戶采用開源的工作流引擎了,這樣積累的使用經驗可以成為公司的財富,只要把核心人員留住,就不用每個項目都去購買一個商業工作流了,節約成本;可不可以這么認為:商業工作流的市場本來就很小呢?
4、12月到新疆出了趟差,然后就是全力開發新疆的項目了。這是一個大集中的項目,也就是一套系統,所有分公司一起使用,最 緊迫的問題就是組織結構、權限以及數據(包括流程)的分級管理了?,F在是業務需求基本都滿足,但是可以想象未來性能的壓力,工作還會有很多。
個人技術:
1、上半年看過一些敏捷和UML的書籍。敏捷感覺已經是一個被用濫的詞語,人人頭上都頂著一個敏捷的帽子,就像言必稱 spring"hibernate一樣,有些惡心了??催^這些書,其實體會最深的還是如何開發出一個大家都能讀懂的代碼,如何與他人交流,能讓別人看懂的代碼就是好代碼。至于UML,好像也能畫上和看懂幾個了。
2、最后一個季度和朋友一起翻譯了《Enterprise AJAX》這本書,重新對ajax有了興趣,翻譯確實是一件辛苦的事情,但是現在回憶起來卻很是覺得有意義。最直接的就是翻譯水平有了很大長進,然后就是ajax有了一些新的認識?,F在看Ext的代碼,想著能否有擴展為類swing框架的可能性。期間參與了滿江紅組織的seam翻譯工作,自己做的工作很少,純屬充數,算是了解了一把seam。
3、我和老婆說,怎么今年就感覺進步沒有去年那么明顯呢?老婆說,因為你去年起點太低!于是釋然。
生活:
1、年初買了房子了,注明一下:是在老婆強烈要求下買的。地點在燕郊。
2、關注了廈門PX、上海磁懸浮,除去工作,開始關注很多東西,也開始看歷史。
08的展望:
1、結婚
2、開發一個基于js的工作流設計器,能否完成?
3、做了3年的開發工作了,工作上能否有新的挑戰?
4、多看點非技術書,多出去轉轉,善待自己和親人。
| |||||||||
日 | 一 | 二 | 三 | 四 | 五 | 六 | |||
---|---|---|---|---|---|---|---|---|---|
25 | 26 | 27 | 28 | 29 | 30 | 31 | |||
1 | 2 | 3 | 4 | 5 | 6 | 7 | |||
8 | 9 | 10 | 11 | 12 | 13 | 14 | |||
15 | 16 | 17 | 18 | 19 | 20 | 21 | |||
22 | 23 | 24 | 25 | 26 | 27 | 28 | |||
29 | 30 | 1 | 2 | 3 | 4 | 5 |
關注工作流和企業業務流程改進。現就職于ThoughtWorks。新浪微博:http://weibo.com/ronghao100
常用鏈接
留言簿(38)
隨筆分類
- ajax相關(9)
- cms(7)
- Head First Process-深入淺出流程(15)
- j2se基礎(6)
- JbpmSide(6)
- OOA/OOD(4)
- SOA、BPM(26)
- 工作日志(24)
- 工作流jbpm3(10)
- 張小慶,在路上(42)
- 心情小站(24)
- 權限相關(12)
- 表現層相關(4)
- 轉載(4)
隨筆檔案
- 2013年8月 (1)
- 2012年12月 (1)
- 2012年1月 (3)
- 2011年12月 (2)
- 2011年11月 (2)
- 2011年10月 (3)
- 2011年9月 (3)
- 2011年8月 (7)
- 2011年7月 (4)
- 2011年6月 (3)
- 2011年5月 (5)
- 2011年4月 (6)
- 2011年3月 (4)
- 2011年2月 (2)
- 2010年9月 (1)
- 2010年6月 (1)
- 2010年5月 (1)
- 2010年3月 (4)
- 2010年1月 (2)
- 2009年11月 (5)
- 2009年10月 (4)
- 2009年9月 (1)
- 2009年7月 (1)
- 2009年6月 (2)
- 2009年5月 (2)
- 2009年4月 (1)
- 2009年3月 (4)
- 2009年2月 (2)
- 2008年12月 (1)
- 2008年11月 (1)
- 2008年10月 (1)
- 2008年9月 (2)
- 2008年8月 (2)
- 2008年7月 (2)
- 2008年6月 (3)
- 2008年5月 (4)
- 2008年4月 (1)
- 2008年3月 (2)
- 2008年2月 (2)
- 2008年1月 (4)
- 2007年11月 (3)
- 2007年10月 (3)
- 2007年9月 (2)
- 2007年8月 (4)
- 2007年7月 (1)
- 2007年6月 (12)
- 2007年5月 (2)
- 2007年4月 (1)
- 2007年3月 (8)
- 2007年2月 (6)
- 2007年1月 (4)
- 2006年12月 (4)
- 2006年11月 (3)
- 2006年10月 (1)
- 2006年8月 (2)
- 2006年7月 (3)
- 2006年6月 (3)
- 2006年4月 (1)
- 2006年3月 (2)
- 2006年2月 (2)
- 2006年1月 (4)
- 2005年12月 (7)
- 2005年11月 (12)
文章分類
文章檔案
常去的網站
搜索
最新評論

- 1.?re: 使用Handler來增強Web服務的功能
- asdfasfd
- --ads
- 2.?re: 使用solr搭建你的全文檢索
-
@木哥哥
你的分詞器用的是什么???mmseg貌似可以的 - --陳冠馳
- 3.?re: 使用solr搭建你的全文檢索
-
@marten這是你的solr的schame.xml配置文件有問題。好好檢查下你的配置文件里面的字段什么的配置對著沒
- --陳冠馳
- 4.?re: 討論一下你覺得一個工作流產品好的標準
- 評論內容較長,點擊標題查看
- --深圳非凡信息技術有限公司
- 5.?re: DisplayTag應用
- name="test"從哪里來的,千篇一律的到處使用test卻沒有test的定義,sb
- --qige