extjs筆記

 

1.    ExtJs 結構樹.. 2javascript

2.    對ExtJs的態度.. 3php

3.    Ext.form概述.. 4css

4.    Ext.TabPanel篇.. 5html

5.    Function擴展篇.. 7java

6.    Ext.data.Store篇.. 10node

7.    Ext.data.JsonReader篇一.. 12程序員

8.    Ext.data.JsonReader篇二.. 15web

9.    Ext.data.HttpProxy篇.. 19ajax

10.     Ext.data.Connection篇一.. 20正則表達式

11.      Ext.data.Connection篇二.. 24

12.     Ext.Updater篇一.. 26

13.     Ext.Updater篇二.. 27

14.     JSON序列化篇.. 33

15.     通訊篇.. 35

16.     extJs 2.0學習筆記(Ajax篇) 38

17.     extJs 2.0學習筆記(Ext.data序論篇) 39

18.     extJs 2.0學習筆記(Ext.Panel終結篇) 40

19.     extJs 2.0學習筆記(事件註冊總結篇) 45

20.     extJs 2.0學習筆記(Ext.Panel篇一) 48

21.     extJs 2.0學習筆記(Ext.Panel篇二) 50

22.     extJs 2.0學習筆記(Ext.Panel篇三) 59

23.     extJs 2.0學習筆記(Ext.Panel篇四) 62

24.     extJs 2.0學習筆記(組件總論篇) 66

25.     extJs 2.0學習筆記(Ext.Element API總結) 69

26.     extJs 2.0學習筆記(Element.js篇) 73

27.     extJs 2.0學習筆記(DomHelper.js篇) 76

28.     extJs 2.0學習筆記(ext.js篇) 77

 

 

 

 

 

1.    ExtJs 結構樹

 

2.    對ExtJs的態度

extjs的確是個好東西,可是,它的優勢也就是它的缺點:

  • 加載頁面慢
  • 時間一長,瀏覽器佔內存就會瘋長
  • 服務器端功能極度削弱,除了數據庫操做外,幾乎全部功能都到了客戶端,還得用javascript來寫。
  • 功能全到了客戶端,而客戶端語言javascript的編寫仍是有許多的麻煩,真正精通它的人極少。
  • javascript對於大部分人來講,不易調試
  • 大量存在的javascript代碼難以維護
  • 開發速度極慢。
  • extjs自己還存在一些問題

  正是由於有這麼多的問題,老闆們都得掂量一下了。用它倒底值不值。固然,這兒也得說一下它的優勢:

  • 由於一切都是javascript搞定,因此,界面上的問題不再像之前同樣讓人鬱悶了,客戶端對界面的的操做取得極大的便利,而不像之前同樣,服務器端生成n多垃圾代碼,之前的時代就似乎隔靴搔癢,服務器端企圖佈置好一切。如今不一樣了,客戶端用一個Ext.Ajax.Request請求數據方便,而後,顯示出來也容易。
  • 又回到了c/s時代。c/s讓人神往啊。web該死的無狀態讓人鬱悶
  • 學習extjs的一個極大的好處,全部當前web開發界面上的需求均可以在這兒找到答案。經過研究它的代碼,咱們能夠開發出本身的ajax框架來,能夠寫出適合於本身的widgets來。而不用揹着extjs那個大烏龜殼。

  我認爲,不宜用extjs來開發整個應用,可是,在極爲須要的地方用一用,仍是蠻好的,整個站點都用它那就麻煩了。如今我對於選擇ajax框架有了一點心得。

  不要使用extjs來開發,可是,必定要學習、研究它,研究它以後纔會曉得,咱們寫代碼應當這麼寫才優美、才合適。研究了它後就應當選一款輕量型的框架了。而後本身寫組件。用以取代:Ext.Window、Ext.TabPanel、Ext.Panel這些好東西。

  研究了extjs,我敢說:一覽衆山小啊!什麼prototype、dojo、jQuery之類,就容易多了。

 

  真正要用的ajax框架,我看,倒不如選擇prototype,它是個輕量型,我以爲,一個ajax,只要封裝了三個東西就好了:

  1、Element。把dom元素要封裝一下,加入動畫、求取、設置各類參數值的功能

  2、XMLHttpRequest,要把它封裝一下,這個全部框架都作了

  3、把事件機制要封裝一下,最好像extjs同樣,xxx.on('click',function(){});就成了。

  有了這三個就差很少了,那些什麼window、tabs,網上多的是代碼,搞些下來改篇改篇就成了。

  關於prototype,我找到了它的中文文檔(1.5的),1.5的大小是93.7k,事實上,這個大小還能夠縮小,能夠使用工具去掉多餘的空格,差很少了。

 

3.    Ext.form概述

  Ext.form中封裝了是輸入組件。input、textArea、frameSet、form等元素都被包裝起來了。我剛纔發了點時間對它的類圖分析了一下,用StartUML作了圖以下:

 

  Ext.form中的組件太多,實在不大

4.   Ext.TabPanel篇

  Ext.TabPanel這個東西是最經常使用的組件之一,它繼承自Ext.Panel。看了一個下午的源代碼,對它的一些基本原理有所瞭解了。

  下面要講一些問題,詳細實例可參看本欄的 技術教程www.gjrencai.com

  1、組件的組成:

  由於繼承自Ext.Panel,因此,它也是由header、tbar、body、bbar、footer這幾個部分構成,有人問:TabPanel的面板標籤是在哪兒呢(就是你點擊換頁的東西)?它默認是放在header中的。可是,若是設置了:tabPosition的話就不必定了,tabPosition可取兩個值:top、bottom。因此,標籤能夠是放在下面,可是,Ext目前還不支技放在左邊、右邊。

  那麼,不一樣的標籤是用什麼元素來組織的呢?用ul。一頁對應一個li。li的id的取值有規律哦,它的取值公式以下:tabpanel.id+tabpanel.idDelimiter+面板的id。正是由於有了這個規律,才能根據點擊的標籤而找到對應的面板。這個問題是一大主題,在下面講。

  這是面板的標籤,下面的面板呢?簡單!!!一個Ext.Panel對應一個面板,注意:這兒的面板是沒有header的,若是你想tab.items.get(1).header,在這兒,header===undefined。爲何爲面板定義的title會對應到標籤中去呢?這個是TabPanel的特地處理的。至於換頁效果是怎麼出來的?CardLayout。這下組件的大概結構都清楚了。還有不明白,本身new Ext.TabPanel({……})一個,而後在FireBug下面去查看dom結構,就一清二楚了。

  2、處理標籤的事件

  爲何要研究這個問題?有需求的,如何在鼠標移到標籤上時就顯示對應的面板呢?默認狀況下,TabPanel是不支持這個功能的,可是,這個功能有時是須要的。這兒有點小技巧。

  看Ext.TabPanel源代碼中關於標籤的事件處理:

        this.strip.on('mousedown', this.onStripMouseDown, this);
        this.strip.on('click', this.onStripClick, this);
        this.strip.on('contextmenu', this.onStripContextMenu, this);
        if(this.enableTabScroll){
            this.strip.on('mousewheel', this.onWheel, this);
        }

  這段代碼寫在initEvents函數中,先解釋一下,this.strip是指頭部放標籤的那個ul元素,相信,98%的讀者會想,要註冊事件也應當是爲li元素註冊,怎麼會通通註冊到ul這個父容器上面呢?原理就是事件冒泡。關於事件傳遞的原理,本人在下一文中有詳細的實驗、明確的結論,再也不贅言。

  ul元素捕獲了事件,怎樣在事件處理函數中得知倒底是哪一個li發生了事件呢?Ext寫了個函數:findTargets。詳情請見以下代碼:

    findTargets : function(e){
        var item = null;
        var itemEl = e.getTarget('li', this.strip);
        if(itemEl){
            item = this.getComponent(itemEl.id.split(this.idDelimiter)[1]);
            if(item.disabled){
                return {
                    close : null,
                    item : null,
                    el : null
                };
            }
        }
        return {
            close : e.getTarget('.x-tab-strip-close', this.strip),
            item : item,
            el : itemEl
        };
    },

    // private
    onStripMouseDown : function(e){
        e.preventDefault();
        if(e.button != 0){
            return;
        }
        var t = this.findTargets(e);
        if(t.close){
            this.remove(t.item);
            return;
        }
        if(t.item && t.item != this.activeTab){
            this.setActiveTab(t.item);
        }
    },

  一切的關鍵就在於li元素的id的命名規則,從中取出對應的面板的id,這樣就能getComponent,從而得到對應的面板引用,再setActiveTab就辦成了。至於getTarget這個是EventObject中封裝的函數,做用是在事件傳播路徑上查找知足指定選擇條件的元素。這個函數的詳情見它的源碼。

  到了這裏,以前所講的鼠標懸停問題只要依照方面方法解決就是了,切記,不要處理mouseout事件,否則,事情就麻煩了,詳情見我之前寫過的關於mouseover事件的一篇文章。

 

 

5.    Function擴展篇

 

  ExtJs對JavaScript的內建對象進行了擴展,對什麼Object、Date、Array、Function、String的擴展,擴展方法想必諸位都爛熟於心了:用prototype的辦法。這一篇講一講Function擴展的精妙之處,之因此忽然研究這個問題,是由於我在研究Ext.data.Store的源代碼時,看到一行代碼:

  this.reader.onMetaChange = this.onMetaChange.createDelegate(this);

  當初,我在研究Ext.js中的代碼時,對於Function的幾個擴展想不透、看不明,今日大悟。且見擴展的源代碼:

    createDelegate : function(obj, args, appendArgs){
        var method = this;
        return function() {
            var callArgs = args || arguments;
            if(appendArgs === true){
                callArgs = Array.prototype.slice.call(arguments, 0);
                callArgs = callArgs.concat(args);
            }else if(typeof appendArgs == "number"){
                callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
                var applyArgs = [appendArgs, 0].concat(args); // create method call params
                Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
            }
            return method.apply(obj || window, callArgs);
        };
    },

  createDelegate函數的做用是,爲指定函數建立一個回調函數,注意是建立一個新的函數返回,它返回的是一個新函數。我之前一直不明白,爲何要這麼作,就像上面紅色的那行代碼,相信大夥與我同樣,都在想,爲何不是寫成這樣:

  this.reader.onMetaChange=this.onMetaChange;

  不是應當這樣寫的嗎?若是用過dotnet,那麼委託必定是曉得了,javascript中的函數跟c#的委託同樣,有很相近的意義,爲何c#中能這樣寫,JavaScript中不能這樣寫呢?

  一切都由於this,this這個東西見風使舵,像上面onMetaChange這函數,實際調用時是在reader中,那麼若是onMetaChange中使用了this關鍵字,那麼,this是指向reader的,而不是指向onMetaChange的定義環境所對應的this。而事實上,咱們每每想把這個this指向函數的定義環境,這也正是回調的最招人喜歡的地方,然而,由於this的問題,回調就不能像上面那樣直接賦值。還得作些手腳,得讓函數調用時scope爲當前定義環境。

  改變一個函數執行的scope,熟翻JavaScript的兄弟必定曉得要用:call、apply。至此,createDelegate的產生背景、做用都做了個交代。

  createDelegate(this),調用時,通常直接傳個this就好了,當真是妙啊。事實上,我上面講的一通道理清楚了,這個函數的代碼就沒有祕密可言了。關鍵就是一個this。我如今感嘆,你對JavaScript的造詣與你對this的領悟層次成正比

  既然講了createDelegate,其餘幾個擴展函數一併講了。

    createCallback : function(/*args...*/){
        // make args available, in function below
        var args = arguments;
        var method = this;
        return function() {
            return method.apply(window, args);
        };
    }

  也是建立調用者的回調,不過,回調函數的scope爲window。至關於createDelegate(window)。沒什麼講的。

    defer : function(millis, obj, args, appendArgs){
        var fn = this.createDelegate(obj, args, appendArgs);
        if(millis){
            return setTimeout(fn, millis);
        }
        fn();
        return 0;
    },

  此函數調用一次就讓函數延遲調用一次。對setTimeout的封裝罷了。若是沒有定義延時參數,那麼就立刻執行。這個函數也沒有技術性可言。

    createSequence : function(fcn, scope){
        if(typeof fcn != "function"){
            return this;
        }
        var method = this;
        return function() {
            var retval = method.apply(this || window, arguments);
            fcn.apply(scope || this || window, arguments);
            return retval;
        };
    },

  這個函數就有點意思了,剛開始研究ext.js的時候尚未看明白,它的做用是在返回一個函數,此函數先調用「調用函數」,後調用傳遞進來的函數。這句話可能還沒說清,見示例以下:

  function A(){alert("第一個執行!");return 1;}

  function B(){alert("第二個執行!");return 2;}

  function C(){alert("第三個執行!");return 3;}

  var D=A.createSequence(B).createSequence(C);

  var result=D();

  上面代碼產生的效果是:

  第一彈出框顯示:第一個執行!

  第二彈出框顯示:第二個執行!

  第三彈出框顯示:第三個執行!

  result的值爲:3

  這下子諸位都明白了吧。用過dotnet的知道,委託變量有這種相似的功能。就是累加執行的效果。

    createInterceptor : function(fcn, scope){
        if(typeof fcn != "function"){
            return this;
        }
        var method = this;
        return function() {
            fcn.target = this;
            fcn.method = method;
            if(fcn.apply(scope || this || window, arguments) === false){
                return;
            }
            return method.apply(this || window, arguments);
        };
    }

  這個函數也有點意思,有創意,它返回被調用函數的回調,這個回調是條件執行的,執行條件是createInterceptor傳入的那個函數返回真。示例代碼以下:

  function A(){}

  var B=A.createInterceptor(function(i){return i>0;});

  B(1),則A被執行,若是調用B(-1),A則不被執行。B的做用就是若是傳入的第一個參數的值大於0時A才被執行,不然不執行。

  至關於原有函數的功能不變,只是加個執行條件。這個想法着實巧妙。這一招如今想來,也能夠用到c#中。

 

6.    Ext.data.Store篇

  Ext.data.Store,這個東西是JavaScript版的DataTable啊。貌似其餘Ajax框架都沒有這個玩意啊。可見啦,Ext是真的打算把b/s開發從新變成c/s開發啊。哈哈哈。便宜我等了。待某細研之。

  Store類提供對記錄集(Record)的包裝,經過前面的研究可知,DataProxy取數據(url或數組或xml或json),DataReader用於從不規範的數據取出並格式化指定結構的記錄集。記錄的結構由Record.create建立。

  DataProxy經過對Connection的調用取得數據(Response)後,在回調中調用DataReader的read函數,從而把response中的數據解析成記錄集,這個記錄集將再以回調參數的形式傳出來,store實現這個回調,並把裏面的Recodrd[]取出來,放到data這個成員中。store.data是一個MixedCollection對象,MixedCollection做什麼用的前面也講過,它本質就是一個容器,ExtJs確實很好,連容器類都寫了。

  有了store.data,數據進了這兒,就好辦了,store調用MixedCollection的功能,實現了一些通用的函數,如取指定成員、查詢、遍歷、事務等等,這些都不足道。什麼提交修改、取消修改的功能倒是根源於Record。Record類自身就封裝了這個功能,Store中只是再次封裝罷了,這個原理也很簡單。看代碼即知。

  上面講的是通用原理,是大概,下面揀緊要的代碼說一下。

  它定義了構造函數,繼承自Ext.Observable。第一行代碼就是個重點:

  this.data = new Ext.util.MixedCollection(false);

  這是定義data,全部記錄都將保存在它裏面。

    this.baseParams = {};
    // private
    this.paramNames = {
        "start" : "start",
        "limit" : "limit",
        "sort" : "sort",
        "dir" : "dir"
    };

  baseParams將在調用HttpProxy時用到,它將做爲params附加到url末尾。這個東西沒有懸念。至於paramsNames用於保存參數名,start、limit應當用於分頁,sort、dir用於排序,不過,我看了通篇的代碼,發現,Store自己不提供任何其餘分頁、排序功能的實現,仍是得依靠服務器端的。只不過,這兒提供一種統一的方式罷了。

    if(config && config.data){
        this.inlineData = config.data;
        delete config.data;
    }
  意思是說,若是建立store時,設了config,且config.data存在,那麼,將直接從config.data中loadData。構造函數後面一點就有。inlineData這個屬性沒活多久就被delete了。

    if(this.url && !this.proxy){
        this.proxy = new Ext.data.HttpProxy({url: this.url});
    }

    if(this.reader){ // reader passed
        if(!this.recordType){
            this.recordType = this.reader.recordType;
        }
        if(this.reader.onMetaChange){
            this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
        }
    }

    if(this.recordType){
        this.fields = this.recordType.prototype.fields;
    }

  就是根據config中的狀況,建立成員:proxy,reader,recordType,onMetaChange。這了這四個,就好方便在下面定義的load中加載數據並徹底記錄集的封裝。說出來一文不值。

  this.modified = [];

  這個東西用於保存那些有修改過的記錄的舊值。之因此能取消修改,正是源於此啊。

  關於addEvents那個語句,就不必講了,大夥都懂。

    if(this.proxy){
        this.relayEvents(this.proxy,  ["loadexception"]);
    }

    this.sortToggle = {};
 if(this.sortInfo){
  this.setDefaultSort(this.sortInfo.field, this.sortInfo.direction);
 }

    Ext.data.Store.superclass.constructor.call(this);

    if(this.storeId || this.id){
        Ext.StoreMgr.register(this);
    }
    if(this.inlineData){
        this.loadData(this.inlineData);
        delete this.inlineData;
    }else if(this.autoLoad){
        this.load.defer(10, this, [
            typeof this.autoLoad == 'object' ?
                this.autoLoad : undefined]);
    }

  第一個語句中主要就是一個relayEvents,意爲延遲事件,這個延遲不是時間延遲哦。它是將當前對像的某些事件處理函數做爲另外一個對象的處理函數,同者共享,事實上,它的做用就是利用另外一對象的事件來觸發本對象的事件,從而引起事件處理函數的執行(說得太拗口了吧)。

  那個inlineData上面講了的,如今應驗了,很少講。從這兒能夠看出,若是已從config中傳過來數據,那麼以直接傳的數據爲準,若是沒有直接傳數據,而是經過url,且autoLoad爲true,這時就在構造函數中加載數據且徹底數據的封裝。

  重點代碼至此講了一半,另外一半就是load、loadRecords了。

7.    Ext.data.JsonReader篇一

嘿,別看關鍵就在這兒,事實上,它的代碼不多的哦。加上註釋才219行。研究研究。

  有個事要說一下:DataProxy的子類呢,都有一個load來加載數據,DataReader的子類呢,都有一個read來讀取數據。

  而Ext.data.JsonReader有兩個關鍵函數:read、readRecords。好了。來研究一下。

  Ext.data.JsonReader = function(meta, recordType){
   
   meta = meta || {};
   
   Ext.data.JsonReader.superclass.constructor.call(this, meta, recordType || meta.fields);
  };

  這是構造函數。簡單。meta是數據格式定義,recordType是記錄類型。其中recordType能夠是一個定義記錄的數組,也能夠不傳,而把記錄的各個字段的定義放到meta中的fields字段中。且看它對父類構造函數的調用:

  Ext.data.DataReader = function(meta, recordType){
   this.meta = meta;
   this.recordType = Ext.isArray(recordType) ?
   Ext.data.Record.create(recordType) : recordType;
  };
  
  Ext.data.DataReader.prototype = { };

  這下全明白了吧。recordType能夠是記錄類型,能夠是字段定義數組,還能夠不傳。

  因此,構造函數就是定義兩個屬性:meta、recordType。這兩東西后面有用。

  這個meta、recordType組成如何?這個必須說明,否則,這個類也就無法用了。

  meta:

  totalProperty    json數據中,保存總記錄數的屬性

  successProperty   json數據中,保存是否返回成功的屬性名

  root        json數據中,保存記錄集的屬性的屬性名

  id         json數據中,記錄中主鍵所對應的列的屬性名

  recordType

  這個東西,事實上要去看Ext.data.Record的create函數的文檔,我且把它翻譯一下,以下:

create( [Array o] ) : function

建立包含指定字段結構的繼承自Ext.data.Record的類。靜態方法。

參數:
  o : Array
    一個定義記錄結構的字段信息數組。每一個數組元素包含name,其餘可選的有:mapping、type。經過它們,可讓Ext.data.Reader從一個數據對象中獲取各字段的值。每一個字段定義對象均可能包含以下屬性:

     name : String
     在記錄中標誌一個字段的名字。它一般用於引用指定字段,例如,在定義Ext.grid.ColumnModel的dataIndex屬性時,要傳過去的。
     
     mapping : String
     當在Ext.data.Reader中建立記錄時,如何將json對象中指定屬性值映射到此字段。

     type : String
     字段的類型,可能值爲:
       auto(默認值,沒有任何轉化)、string、int、float、boolean、date
         
            sortType : Mixed
     Ext.data.SortTypes中的一個成員。

     sortDir : String
     排序方式,"ASC"或者"DESC"。

     convert : Function
     若是要對這個字段的值進行一些物殊處理,這時須要一個能定製的回調,用它來手工處理值。它的參數以下:
        v : Mixed
        經過mapping映射找到的值。已從json中取出來的。
        rec : Mixed
        在json中的,對應於此記錄的json對象。

     dateFormat : String
     用於Date.parseDate函數的格式化字符串。

     defaultValue : Mixed
     當字段值在原數據中不存在時所取的默認值,默認爲空字符串。

用法:

var TopicRecord = Ext.data.Record.create([
    {name: 'title', mapping: 'topic_title'},
    {name: 'author', mapping: 'username'},
    {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
    {name: 'lastPost', mapping: 'post_time', type: 'date'},
    {name: 'lastPoster', mapping: 'user2'},
    {name: 'excerpt', mapping: 'post_text'}
]);

var myNewRecord = new TopicRecord({
    title: 'Do my job please',
    author: 'noobie',
    totalPosts: 1,
    lastPost: new Date(),
    lastPoster: 'Animal',
    excerpt: 'No way dude!'
});
myStore.add(myNewRecord);

 

  好了,這一篇差很少了,未盡內容放下一篇中了。

 

8.    Ext.data.JsonReader篇二

有了上一篇中所講內容,通常狀況下就能夠應付了,不過,JsonReader有一些細節問題,還要細究。待某家一一道來。

  構造函數已講,下面依代碼順序講解了。

    read : function(response){
        var json = response.responseText;
        var o = eval("("+json+")");
        if(!o) {
            throw {message: "JsonReader.read: Json object not found"};
        }
        return this.readRecords(o);
    },

  這個是整個JsonReader的關鍵所在了。君可找到Ext.data.HttpProxy中的loadResponse函數,裏面有這麼一行代碼:

  result = o.reader.read(response);

  可見,是proxy裏面調用reader.read方法才得以取出結果集的。這是要代表:read乃JsonReader三軍中軍之所在。read又調用readRecords,read把json字符串轉化爲對象而後交給readRecords。這個本無不妥,可是,asp.net中,它的結果有點曲折,結果是放在o.d中,而不能直接從o中取得。因此,事實上應當這麼寫:this.readRecords(o.d)這就成了。繼續往下面看:

    onMetaChange : function(meta, recordType, o){

    }

  這個函數說是要由store實現的,如今不知道它的用處。還往下看:
    simpleAccess: function(obj, subsc) {
     return obj[subsc];
    },
    getJsonAccessor: function(){
        var re = /[\[\.]/;
        return function(expr) {
            try {
                return(re.test(expr))
                    ? new Function("obj", "return obj." + expr)
                    : function(obj){
                        return obj[expr];
                    };
            } catch(e){}
            return Ext.emptyFn;
        };
    }(),

  取一對象的屬性有兩種方法,前面都已說起:

  1、obj.xxxx

  2、obj[xxxx]

  這兩種都行。可是,若是傳過來一個對象,已知其對象的引用obj,可是有的只是它的屬性名的字符串,這時就能夠用第二種方法取出,可是,如屬性名中含[],那麼就不大方便了,又或者是屬性又帶屬性,這事也只能用第一種方法。這兩個函數正是爲事而來。且看那getJsonAccessor,着實巧妙,函數返回一函數,這不是巧妙之處,這個我之前就見識了,關鍵在於new Function("obj","return "obj."+expr)。多麼巧妙啊。此之中巧,不足以言語道哉。

  這下面就是真正的好戲了,看一看readRecords函數。

        this.jsonData = o;
        if(o.metaData){
            delete this.ef;
            this.meta = o.metaData;
            this.recordType = Ext.data.Record.create(o.metaData.fields);
            this.onMetaChange(this.meta, this.recordType, o);
        }

  定義一個jsonData屬性以保存原始json對象。而後若是傳過的json對象中就有metaData。那麼,就用它自帶的meta來取代JsonReader構造函數中所傳入的meta。以原來自帶的爲主。這個功能方檔不曾說起,但我輩不可不察也。

        var s = this.meta, Record = this.recordType,
            f = Record.prototype.fields, fi = f.items, fl = f.length;

  有人不理解了,爲何非得這樣呢?這是節省帶寬啊。若是這些東西之後多說現幾回,那麼每一個用戶都要多下載一些東西,成千上萬人能節省多少啊。

        if (!this.ef) {
            if(s.totalProperty) {
             this.getTotal = this.getJsonAccessor(s.totalProperty);
         }
         if(s.successProperty) {
             this.getSuccess = this.getJsonAccessor(s.successProperty);
         }
         this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
         if (s.id) {
          var g = this.getJsonAccessor(s.id);
          this.getId = function(rec) {
           var r = g(rec);
           return (r === undefined || r === "") ? null : r;
          };
         } else {
          this.getId = function(){return null;};
         }
            this.ef = [];
            for(var i = 0; i < fl; i++){
                f = fi[i];
                var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
                this.ef[i] = this.getJsonAccessor(map);
            }
        }

  由於要根據meta.id、meta.root。這兩值都是字符串,這就要用到前面定義的getJsonAccessor函數了。這兒正是來生成幾個取json對象中屬性的函數,如:getTotal、getSuccess、getRoot、getId、ef數組,一個ef數組就解決了屬性映射的問題,真是漂亮。

     var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
     if(s.totalProperty){
            var v = parseInt(this.getTotal(o), 10);
            if(!isNaN(v)){
                totalRecords = v;
            }
        }
        if(s.successProperty){
            var v = this.getSuccess(o);
            if(v === false || v === 'false'){
                success = false;
            }
        }

  這兒是求totalRecords、success。有一事要注意:其中:

  c = root.length, totalRecords = c

  這上c後面要用來循環的,而totalRecords是要返回的,然後,又求了totalRecords,這個意思是:若是結果中沒有totalProperty這一屬性,那麼就自動求取,若是存在,則以定義的totalProperty爲主,因而可知,totalProperty是無關緊要的。這個問題文檔未曾見之。諸位可無憂矣。

     var records = [];
     for(var i = 0; i < c; i++){
      var n = root[i];
         var values = {};
         var id = this.getId(n);
         for(var j = 0; j < fl; j++){
             f = fi[j];
                var v = this.ef[j](n);
                values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue, n);
         }
         var record = new Record(values, id);
         record.json = n;
         records[i] = record;
     }
     return {
         success : success,
         records : records,
         totalRecords : totalRecords
     };

  這是剩餘的代碼了,由for(var i = 0; i < c; i++)可知,循環的時候仍是用root.length的。而不是totalProperty。這個要分清,事實上,totalProperty只是直接返回罷了,未作任何改動。裏面就轉化成Record了。其中,這個ef數組用得巧妙。類型轉化用了convert。這個東西前文已講,不足道哉。

  var record = new Record(values, id);

  id=this.getId(n),可見啦,id並不是前文所說的主鍵,它只是一個用來作客戶端惟一編號的東西,如對此有疑,可見於Ext.data.Record類。

  record.json = n,json這個屬性我在Ext.data.Record類中並不曾得見,諸君注意了,這個東西也許會有用。另外,readRecords返回的不僅是一個records數組,而是一個json對象,包含success、records、totalRecords。

  至此,JsonReader源代碼分析完畢,呵呵,由於這個類代碼量較少,故講得詳細。

  

9.    Ext.data.HttpProxy篇

關於Ext.data中各個類的關係圖我在前面已經作了一個,不用多言。其實啊。關於數據的顯示,通常要經歷三個流程:DataProxy-->DataReader-->Store。固然,三個部分都得是具體的類,這三個是抽象類。

  若是按照通常性的理解,那麼應當先從Proxy開始了。

  出人意料:DataProxy的代碼就是一空架子。且看:

Ext.data.DataProxy = function(){
    this.addEvents(
        'beforeload',
        'load'
    );
    Ext.data.DataProxy.superclass.constructor.call(this);
};

Ext.extend(Ext.data.DataProxy, Ext.util.Observable);

  就是加兩事件,從Observable繼承了。如此而己,看代碼就看晴晰了。再看一看HttpProxy,它的代碼也就一百來行。比起其餘類來講,真是小巫見大巫了。

  先爲Ext.data.HttpProxy給個描述吧:從一個Ext.data.Connection中讀取數據到一個數據對象、從Ext.data.DataProxy繼承的類。這個類不能跨站出數據,記住了

  此類構函數的文檔中說:

  HttpProxy( Object conn )

  conn是一個connection對象或者是一個傳給Ext.Ajax.requestoptions。若是傳給它的是一個options,那麼,將使用Ext.Ajax.request獲取數據。

  這個地方要注意一下。

  下面來說一下load函數,HttpProxy的一切精髓皆在於此。HttpProxy惟一的一個公開的函數。

load( Object params, Ext.data.DataReader reader, Function callback, Object scope, Object arg ) : void

從一個配置好的Ext.data.Connection中讀取數據,它經過傳遞過來的實現自Ext.data.DataReader的對象來讀取數據放到一個Ext.data.Records中。而且,在callback中處理這個結果數據。

參數:
  params : Object
  用於Ext.data.connection.request的options中的params。

  reader : Ext.data.DataReader
  被用來轉化數據的。把數據轉化成Ext.data.Records的形式。

  callback : Function
    用於處理最終結果的回調,當HttpProxy取得connection中的數據,而後交給reader轉化了數據後,所得結果集就會交給callback。它的參數以下:
     object result
     一個記錄集對象。

     object arg
     就是load函數中傳過來的arg。

     boolean success
     是否請求數據成功。

  scope : Object
  用於callback的scope。

  arg : Object
  用於callback的arg。
  

  原本看文檔沒看出明堂來,一結合代碼就明白了。原來callback就是用來處理數據的。若是正常的話,這個callback應當是由store來提供吧。它實現這個接口,而後把數據從HttpProxy中接手過來。而後就後就得包裝成store了。這還只是個人猜想,具體狀況就要看store的代碼了。

  如今,一切都明顯了,取數據是connection的事,不用咱們費心了,轉換數據成記錄集,這個是reader的事,也不用咱們費心了。HttpProxy的做用事實就是兩者的外觀類。如今就要研究一下Ext.data.JsonReader了。

 

10.         Ext.data.Connection篇一

ExtJs之因此能異步請求數據,全依賴於Ext.data.Connection。而Ext.Ajax只不過是Ext.data.Connection的一個實例罷了。固然Ext.Ajax比Ext.data.Connection多了一個函數:serializeForm(form),這個函數的做用是把一個表單裏面的表單元素序列化。結果形式爲:name1=value1&name2=value2……不過,若是是個人話,通常不會用這個東西,由於日常都是傳json數據的,固然,若是不是請求WebService,而是請求aspx頁面,那麼這個東西仍是有點用的。

  先把它的官方文檔翻譯一下吧。

全  稱:Ext.data.Connection
命名空間:Ext.data
定義 於:Connection.js
類  名:Connection
子  類:Ajax
父  類:Observable

  這個類封裝了到頁面所在主機的鏈接,容許經過一個配置好的URL來請求數據,也能夠臨時在請求時傳遞一個URL。

  經過這個類得到的請求都是異步的,而且立刻返回,調用request後,它並不立刻返回數據,要處理數據,要在調用request時傳入的options對象中,配置callback或者是success、failure。這三個是回調函數。其區別將在下文具體交待。固然,你也能夠使用Connection的事件處理來作一些事情。

  注意:若是你是要上傳文件,你的回調、事件處理函數將不會得到一般意義上的response對象。上傳經過IFrame來捕獲,因此就沒有XMLHttpRequest了。這時,response仍是被建立,不過,它的responseText等於IFrame的document.innerHTML,responseXML等於IFrame的document中的xml數據。固然,這個前提是它們存在的時候。


  這意味着必面回一個合法的XML或HTML document。若是返回的是JSON數據,那麼建議你把數據放到<textarea>標記中,返回時經過正則表達式從responseText中取出來了。若是返回的是XML數據,建議放到CDATA裏面,經過標準DOM方法從responseXMl中取得數據。


Options
autoAbort : Boolean
取消當前請求,無論當前請求是否是存在。默認值爲false。


defaultHeaders : Object
默認頭部,每一個HTTP請求分紅兩部:頭部、數據。數據就是post的部分,頭部包含了請求的一些基本屬性,此對象定義了用當前connection對象發起的請求的默認頭部,默認值爲undefined。


disableCaching : Boolean
是否爲GET請求加入一個惟一標誌的參數緩存。

extraParams : Object
通常狀況下,加在encodeURL(params)後面。默認值爲:undefined。

method : String
就是http請求的method屬性。默認狀況下是未定義的(undefined);若是沒有設置,可是調用request時設了params,那麼將使用POST方式,不然使用GET。


timeout : Number
請求超時,默認值爲:30000。單位是millisecond(毫秒?)。


url : String
用此connection對象發起的請求的默認URL。默認值爲:undefined。


無公共屬性


公共函數(只講connection自身的,不包括從Observable中繼承來的)
Connection( Object config )
構造函數,沒有懸念。


abort( [Number transactionId] ) : void
取消指定id的請求,若是沒有指定則取消當前請求。


isLoading( [Number transactionId] ) : Boolean
判斷指定id的請求是否是正在請求中(?)。


request( [Object options] ) : Number
發送一個HTTP請求到遠程主機上。
重點:Ajax服務請求都是異步的,而且這個請求將在response(響應)返回以前返回,也就是說,你絕對沒法經過此函數來直接返回數據,你得經過定義回調函數來處理返回的數據。

參數:
  options : Object
    一個可能包含下面屬性的對象:

        url : String (Optional)
       
請求對應的URL,默認值是connectionoptions配置的那個url

    params : Object/String/Function (Optional)
    用於提供url後面的請求參數(俗稱查詢字符串),能夠是json對象,能夠是直接的字符串,能夠是一個函數。

    method : String (Optional)
    此http請求的method。默認值爲connectionoptions中配置的method。若是沒有設置它,那麼就要看params是否設了,若是設了就以POST方式請求,若是沒有就以GET方式請求,注意:method名是大小敏感的,必須全面大寫。

    callback : Function (Optional)
    不管請求成功仍是失敗它都被執行,其參數以下:
       options : Object
       不用說了。
       success : Boolean
       是否請求成功了。
       response : Object
       一個包含響應數據的XMLHttpRequest對象。

    success : Function (Optional)
    請求成功時執行的回調。它的參數以下:
       response : Object
       一個包含響應數據的XMLHttpRequest對象。
       options : Object
       不用說了。

    failure : Function (Optional)
    請求失敗時執行的回調。它的參數以下:
       response : Object
       一個包含響應數據的XMLHttpRequest對象。
       options : Object
       不用說了。

    scope : Object (Optional)
    回調函數執行時所使用的scope

    form : Object/String (Optional)
    將用於構造查詢字符串的form的引用或id

    isUpload : Boolean (Optional)
    當前請求是不是在上傳文件(一般是自動檢測的)
    文件上傳不是經過一般的Ajax技術實現,它們經過在form提交時動態插入一個iframe,返回時又移除這個iframe來實現,一通的英文,就是說響應數據是直接交給瀏覽器的,這時,就有點能理解爲何要用iframe了。由於它返回的東西會被瀏覽器直接插入到document對象下面,直給放當前頁,那麼頁面當前內容將消失。因此,只有放一個iframe中了。且這個iframe得隱藏起來。
    若是返回結果是json,那麼頭部要設一下content-type:text/html

    headers : Object (Optional)
    請求的頭部。

    xmlData : Object (Optional)
    若是有它,那麼params就不會起做用。

    jsonData : Object/String (Optional)
    若是有它,那麼params就不會起做用。

    disableCaching : Boolean (Optional)
    爲真時爲Get請求建立一個param緩存。

    這個options對象也能夠包含其餘你須要用於回調的屬性,大夥都曉得,這個options最後回被傳給回調函數的,因此,也能夠加入本身想要的東西。

    返回值:
    一個請求的id。它用於取消請求。。


事件:
  beforerequest : ( Connection conn, Object options )
  在請求發生以前觸發。

  requestcomplete : ( Connection conn, Object response, Object options )
  請求結束時觸發。

  requestexception : ( Connection conn, Object response, Object options )
  當http請求處於錯誤狀態時觸發。

 

11.         Ext.data.Connection篇二

上一篇主要是紮紮實實地翻譯了一下Ext.data.Connection的官文檔。儘管網上有位大俠也搞了箇中文文檔,可是,有很多遺漏的地方。這篇主要是研究一下文檔中有些語焉不詳的地方,這些問題只能透過研究代碼來解釋了。

  1、Ext.data.Connection是否有依賴的模塊

  有。它創建在一個適配器類:Ext.lib.Ajax的基礎之上,有人看了Ext.js的代碼,發現,Ext貌似沒有什麼底層適配器,事實上,是有的,Ext.lib.Ajax提供了對XMLHttpRequest對象的底層的封裝(我直接用ext-base.js)。

  2、在options中哪些東西會被編碼到url後面

  params、extraParams、form。

  3、url參數與jsonDataxmlData的關係

  這是個很是重大的問題,且見Connection的代碼:

  if((method == 'GET' || o.xmlData || o.jsonData) && p){
    url += (url.indexOf('?') != -1 ? '&' : '?') + p;
    p = '';
  }

  看這三行代碼,以爲實在講不清啦。可是,至少一件事是明白的:若是定義了xmlData、jsonData,且又定義了params/extraParams/form,那麼並不會形成參數無用。仍是照樣傳過去了的。

  至於xmlData與jsonData的優先級關係,這個要看Ext.lib.Ajax的源碼了。源碼以下:

                if(options.xmlData){
                    if (!hs || !hs['Content-Type']){
                        this.initHeader('Content-Type', 'text/xml', false);
                    }
                    method = (method ? method : (options.method ? options.method : 'POST'));
                    data = options.xmlData;
                }else if(options.jsonData){
                    if (!hs || !hs['Content-Type']){
                        this.initHeader('Content-Type', 'application/json', false);
                    }
                    method = (method ? method : (options.method ? options.method : 'POST'));
                    data = typeof options.jsonData == 'object' ? Ext.encode(options.jsonData) : options.jsonData;
                }

  可見,若是同時定義了xmlData和jsonData,那麼將按發送xmlData中的數據,jsonData中的數據被忽略。

  4、那個disableCaching倒底有什麼鳥用?

  貌似是否使用緩存的意思?文檔讓人鬱悶,且見代碼:

  if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
    url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
  }

  原來是加個時間參數。拜託了。搞得咱們一頭的霧水啊。

 

  至此,關於Ext.data.Connection的相關問題都差很少掃清,它的使用例子,前面的「通訊篇」中有代碼。能夠參見。

 

12.         Ext.Updater篇一

  上幾篇中老老實實地把Ext.data.Connection翻了個遍。這是基礎。我記得Ext.Element有一個方法:

load( String/Function url, [String/Object params], [Function callback], [Boolean discardUrl] ) : Ext.Element
直接調用Ext.Updater.update方法處理(它們使用同樣的參數)
參數:
  url : String/Function
  用於請求的url字符串或能返回url的函數。
  
  params : String/Object
  放到url後面的查詢參數

  callback : Function
  當請求完畢時執行的回調

  discardUrl : Boolean
  默認狀況下,每執行一次updatedefaultUrl屬性就會被改爲上一次使用過的url,若是爲真,則這一次除外,不用保存到defaultUrl

  這個函數在前面沒有講過,事實上它是不少問題的基礎,由於一切都創建在Ext.Element基礎之上。它的源代碼爲:

  load : function(){
    var um = this.getUpdater();
    um.update.apply(um, arguments);
    return this;
  }

  超簡單。Element有一個方法getUpdater,用於得到一個Ext.Updater類的實例。而後調用它的update方法。因此,一切的關鍵在Ext.Updater。下面是getUpdater的源代碼:

  getUpdater : function(){
    if(!this.updateManager){
      this.updateManager = new Ext.Updater(this);
    }
    return this.updateManager;
  }

  看Ext.Updater代碼去也。

  上面對於load的做用尚未說明。這兒正經地說一下:用於從一個ajax請求中獲取數據並更新到此元素中。

  Ext.Updater的主要功能有:

  1、基於Ext.Ajax請求數據

  2、能定時發送請求,也就是說能定時更新某一元素

  3、能在更新時顯示一個表示正在加載中的指示器字符串。

  4、提供一個接口用於自定義數據顯示:Ext.Updater.BasicRenderer

  功能仍是蠻強悍的。

  這是初步介紹,下一篇將將Ext.Updater的官方文檔翻譯一下。

 

13.         Ext.Updater篇二

全  稱:Ext.Updater
命名空間:Ext
定義 於:UpdateManager.js
類  名:Updater
父  類:Observable

Element對象提供Ajax式的更新能力。Updater能用於更新Element一次或者使用startAutoRefreshElement具有定時更新的能力。

用法:

//從一個Ext.Element對象得到Updater的引用
var el = Ext.get("foo");
var mgr = el.getUpdater();
mgr.update({
url: "http://myserver.com/index.php",
params: {
  param1: "foo",
  param2: "bar"
}
});
...
mgr.formUpdate("myFormId", "http://myserver.com/index.php");


//或者直接經過Updater構造函數來建立
var mgr = new Ext.Updater("myElementId");
mgr.startAutoRefresh(60, "http://myserver.com/index.php");
mgr.on("update", myFcnNeedsToKnow);

   //從element對象的簡捷調用方式
   Ext.get("foo").load({
        url: "bar.php",
        scripts: true,
        params: "param1=foo&param2=bar",
        text: "Loading Foo..."
   });


總結上一面共計有四種更新方法:
updater.update({……});
updater.formUpdate(formname,url);
updater.startAutoRefresh(second,url);
Element.load({……});

 

公共屬性:

defaultUrl : String
保存updater上一次更新時使用的url。

disableCaching : Boolean
是否在url後面上一個惟一標誌的參數(當前時間,見Ext.data.Connection),默認值爲:Ext.Updater.defaults.disableCaching.


el : Ext.Element
updater使用的element。

formUpdateDelegate : Function
至關於dotnet中的delegate。在別的地方定義,到這兒來調用。回調啦。內部使用方法以下:myUpdater.formUpdateDelegate.createCallback(arg1, arg2)

indicatorText : String
指示器文本(正在加載的時候),默認值爲:Ext.Updater.defaults.indicatorText。

loadScripts : Boolean
輸出的時候是否是加過腳本(?),默認值爲:Ext.Updater.defaults.loadScripts。

refreshDelegate : Function
用於refresh()內的委託,scope使用this。內部使用方法以下:myUpdater.refreshDelegate.createCallback(arg1, arg2)。

renderer : Object
Updater的呈現器(默認值爲:Ext.Updater.BasicRenderer)

showLoadIndicator : String
是否在加載過程當中顯示指示器文本,默認值爲:Ext.Updater.defaults.showLoadIndicator。文檔有誤,應當是boolean類型。


sslBlankUrl : String
空頁面url,用於SSL文件上傳。默認值爲:Ext.Updater.defaults.sslBlankUrl。

timeout : Number
請求超時。單位是秒。默認值爲:Ext.Updater.defaults.timeout。

transaction : Object
當前事務對象,若是沒有當前事務則爲null。

updateDelegate : Function
用於更新(update())的委託。內部使用方式爲:myUpdater.updateDelegate.createCallback(arg1, arg2)

 

公共方法:

Updater( Mixed el, [Boolean forceNew] )
直接建立一個新的Updater對象。


Updater.updateElement( Mixed el, String url, [String/Object params], [Object options] ) : void

不同意. 一個靜態方法. 反對用此函數取代el.load({url:'foo.php', ...})

用法:Ext.Updater.updateElement("my-div", "stuff.php");

abort() : void
取消當前正在執行的事務。

formUpdate( String/HTMLElement form, [String url], [Boolean reset], [Function callback] ) : void

執行一個異步form post。用返回的響應數據更新element。若是form有一個屬性:enctype="multipart/form-data",它表示這是上傳文件,將使用this.sslBlankUrl來阻止IE安全警告。

 參數:
   form : String/HTMLElement
   form的id或者是element。

   url : String
   用於form.action。即提交的網址。

   reset : Boolean
   是否在更新完後重置表單。

   callback : Function
   當事務完畢後執和,它有以下參數:

      el : Ext.Element
      正在執行更新的元素

      success : Boolean
      是否更新成功。

      response : XMLHttpRequest
      響應結果。。

 

getEl() : Ext.Element
得到要更新的元素。


getRenderer() : void
取得當前內容呈現器。到Ext.Updater.BasicRenderer.render看更多的細節。

isAutoRefreshing() : void
是不是定時更新。。

isUpdating() : Boolean
是否處於正在更新中。

refresh( [Function callback] ) : void
用上一次更新的地址(defaultUrl)再次更新一下。若是沒有就立刻返回。
  callback : Function  
  更新完畢後調用。

setDefaultUrl( String/Function defaultUrl ) : void
設置defaultUrl。

setRenderer( Object renderer ) : void
設置呈現器。

showLoading() : void
顯示指示器。

startAutoRefresh( Number interval, [String/Object/Function url], [String/Object params], [Function callback], [Boolean refreshNow] ) : void
把這個元素設置爲自動更新。經過使用stopAutoRefresh來中止自動更新。

stopAutoRefresh() : void
中止自動更新。

update( Object options ) : void

發起一次異步請求,使用請求的響應結果來更新元素內容。

注意:因爲異步請求的通常是遠程主機,因此元素不會在此函數返回時更新。要處理返回的數據,請使用回調或事件。

  參數:
    options : Object
    一個包含以下屬性的配置對象。
    
     url : String/Function
     請求所須要的url或能返回url的函數。

     method : String
     Post或者是GET。全爲大寫。

     params : String/Object/Function
     見Ext.data.Connection中的options.params的說明。

     scripts : Boolean
     當響應數據中包含<script>……</script>,即包含腳本或腳本引用時,是否提取並執行。爲真則執行。默認值爲:Ext.Updater.defaults.loadScripts。若是這個屬性在options中設置了,那麼回調將在此script執行完後再執行。

     callback : Function
     當響應結果已返回時調用,它有以下參數:
       el : Ext.Element
       正在更新的元素的引用。

       success : Boolean
       是否更新成功。

       response : XMLHttpRequest
       包含響應數據的XMLHttpRequest。

       options : Object
       傳給update方法的options。

     scope : Object
     回調使用的scope。

     discardUrl : Boolean
     是否拋棄當前更新的url,不保存到defaultUrls。

     timeout : Number
          超時設置,單位爲秒。默認值爲:Ext.Updater.defaults.timeout。

     text : String
     這個text與indicatorText的區別在於,請見代碼:
     this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";

     nocache : Boolean
     用於Ext.data.Connection.disableCaching。
  

     示例代碼:
     um.update({
         url: "your-url.php",
         params: {param1: "foo", param2: "bar"}, // or a URL encoded string
         callback: yourFunction,
         scope: yourObject, //(optional scope) 
         discardUrl: true,
         nocache: true,
         text: "Loading...",
         timeout: 60,
         scripts: false // Save time by avoiding RegExp execution.
     });


公共事件:

beforeupdate : ( Ext.Element el, String/Object/Function url, String/Object params )
在更新以前觸發。。

failure : ( Ext.Element el, Object oResponseObject )
更新失敗時觸發。


update : ( Ext.Element el, Object oResponseObject )
更新成功時觸發。

 

14.         JSON序列化篇

  ExtJs有一個類:Ext.util.JSON,它提供兩個函數:encode、decode。用於序列化和反序列化,功能蠻強大的,也差很少了,可是,在WebService中序列化DataTable、DataSet時,遇到麻煩。這個問題只有本身解決了。

  其實這個問題簡單的很,沒什麼大不了的。這兒有一篇文章有代碼!就是循環作事嘛。可是,我以爲,若是要用於ExtJs的話,這個代碼還不夠。由於JsonReader好像還須要一些其餘的東西。因此呢,代碼仍是要修正一下的。

  上一篇中,用到了:Ext.util.JSON.decode。事實上,這個函數有簡寫方式的:Ext.decode。事實上Ext類中兩個關JSON序列化的函數:Ext.encodeExt.decode。以方便使用。

  Ext.data.JsonReader須要三個東西:id(主鍵)、root(記錄集的引用)、記錄數。爲此,我修改了上面的代碼,得驗證經過的代碼以下:

public static class Json
{

    public static string toJson(DataTable dt)
    {
        StringBuilder JsonString = new StringBuilder();
        //Exception Handling       
        if (dt != null && dt.Rows.Count > 0)
        {
            JsonString.Append("{ ");
            JsonString.Append("\"count\":" + dt.Rows.Count + ",");
            JsonString.Append("\"rows\":[ ");
            for (int i = 0; i < dt.Rows.Count; i++)
            {
                JsonString.Append("{ ");
                for (int j = 0; j < dt.Columns.Count; j++)
                {
                    if (j < dt.Columns.Count - 1)
                    {
                        JsonString.Append("\"" + dt.Columns[j].ColumnName.ToString() + "\":" + "\"" + dt.Rows[i][j].ToString() + "\",");
                    }
                    else if (j == dt.Columns.Count - 1)
                    {
                        JsonString.Append("\"" + dt.Columns[j].ColumnName.ToString() + "\":" + "\"" + dt.Rows[i][j].ToString() + "\"");
                    }
                }
                /**//*end Of String*/
                if (i == dt.Rows.Count - 1)
                {
                    JsonString.Append("} ");
                }
                else
                {
                    JsonString.Append("}, ");
                }
            }
            JsonString.Append("]}");
            return JsonString.ToString();
        }
        else
        {
            return null;
        }
    }
}
  實驗所得結果以下:

 

  這下子就很明顯了。在客戶端反序列化的方法以下:

  Ext.decode(Ext.decode(response.responseText).d)

  通常的狀況下應當不會傳DataSet吧。實在要傳DataSet也容易。調用上面的就好了。寫個toJson(DataSet ds),ok了。

15.         通訊篇

 javascript經過XHR調用WebService。兩個問題必須解決:

  1、如何傳值給WebService,有什麼格式要求沒有?

  2、如何接收從WebService傳過來的結果?

  此兩者我輩不能不察也。asp.net的WebService默認是序列化成json格式的,因此,咱們在客戶端傳值時,最好用json傳,反映到ExtJs中。就是Ext.Ajax.request({url:'xxxx/method',jsonData:{paramName:value,……},method:'post',success:function(response,options){……}})。這是在ExtJs中進行異步請求的通式。紅色部分就是要傳的值了。要注意的是,paramName必須與服務器端的那些參數名相同,否則,WebService怎麼曉得你傳過去的值是給哪一個參數的呢?這是個約定。

  下面來研究一下傳值的狀況:

  1、若是傳、收數值類型、整型、數組類型

  這個毫無懸念,只要調用Ext.util.JSON.decode(response.responseText).d就能夠取出來。若是是數組,那麼很簡單:Ext.util.JSON.decode(response.responseText).d[x]

  2、若是傳、收的是日期類型

  傳過去沒什麼問題,可是收過來的時候就麻煩了。我試了很久才研究出來。像上面經過:Ext.util.JSON.decode(response.responseText).d獲得的是一個字符串,這個字符串的結構通常是:/Date(1212756402000)/。那個數值聽說是UTC時間,我把它取出來傳到Date裏面來構造日期,結果獲得了一個1970的某日,鬱悶,事實上應當是2008年6月5日纔對。忽然,我靈光一閃,asp.net爲何要在數值外面加個Date()呢,寫了以下表達式,結果成功了:

  eval("new "+eval("/Date(1212756402000)/").source)

  結果爲:Fri Jun 06 2008 20:46:42 GMT+0800

  正確無誤了。eval真是一個好東西啊。

  3、若是傳、收的是集合

  對於客戶端來講,集合有兩種形式,呵呵,這個是在總結JavaScript哦:

  1.數組array[x]

  2.對象成員object.xxxxobject[xxxx]

  傳過去很簡單,沒有懸念。不管WebService中的參數類型爲數組仍是List<xxxx>。對應在這邊都是數組。若是是Dictionary<X,Y>。那麼它對應的就是:object了(上面的第二種狀況)。

  仍是給個代碼出來吧,否則,說服力仍是不夠的:

   Ext.get("btnList").on("click",function(){
        
         var arr=new Array();
         for(var i=1;i<=10;i++) arr.push(i);
        
         Ext.Ajax.request({url:'MyService.asmx/fun5',
                           jsonData:{list:arr},
                           method:'post',
                           success:function(response,options){
                                var result=Ext.util.JSON.decode(response.responseText);
                           }});
    });

  服務器端WebService中的方法爲:

    [WebMethod]
    public List<string> fun5(List<int> list)
    {
        List<string> list2 = new List<string>();
        foreach (int i in list)
            list2.Add("值爲:" + i);

        return list2;
    }

  最後result.d的值爲:

["值爲:1", "值爲:2", "值爲:3", "值爲:4", "值爲:5", "值爲:6", "值爲:7", "值爲:8", "值爲:9", "值爲:10"]

  上面要注意的是:list這個原始參數是不能修改原有值,可是,能在原有值的基礎上增長成員。這個問題比較奇怪,我試着修改原有成員,結果,錯誤希奇古怪。什麼「Ext is not defined」。事實上Ext不可能沒被定義的。

  4、若是傳、收的值爲一個自定義類的引用時

  這是個廣泛性的問題,普遍存在着。本人定義了一個簡單的類來做實驗:

        public class Cat
        {
            public Cat() { }

            public string Name { get; set; }

            public string Desc { get; set; }

            public int Price { get; set; }

            public int Weight { get; set; }
        }

  客戶端JavaScript代碼:

        function Cat(){
            this.Name='';
            this.Desc='';
            this.Price=50;
            this.Weight=1;
        }

       Ext.get("btnCat").on("click",function(){
            
             var cat=new Cat();
             cat.Name="加菲貓";
             cat.Weight=12;
             cat.Price=100;
            
             Ext.Ajax.request({url:'MyService.asmx/fun6',
                               jsonData:{cat:cat},
                               method:'post',
                               success:function(response,options){
                                    var result=Ext.util.JSON.decode(response.responseText);
                               }});
        });

  服務器端WebService裏面的方法:

        [WebMethod]
        public Cat fun6(Cat cat)
        {
            cat.Desc = cat.Desc + "加個隨機數字吧:"+(new Random()).Next(1,20);

            return cat;
        }

  實驗結果result.d的值爲:

  

  注意:這個結果多了個東西:__type。這是asp.net的webservice在序列化返回值時加上去的。這個成員在post到服務器時並無。

  這個中間有個關鍵,那就是在客戶端也要用JavaScript定義一個Cat類.固然,也能夠不定義.這個問題留待各位去研究一下.

  5、傳、收DataTable對象

  儘管我如今搞N層結構,不用傳DataTable了。可是,相信許多兄弟還要直接來傳它。這是個經典問題。

  很差意思啊。我實驗了,結果response.responseText裏面返回了一大通的錯誤信息,說不能把DataTable序列化。這下子沒有什麼直接的辦法的,除非本身寫個類來序列化DataTable。這個須要研究一下了。

  6、要調用的WebService的方法沒有參數,可是有返回值時

  這個時候要當心了,要注意幾個問題:

  1.在Ext.Ajax.request({……})中不要加jsonData這個成員了。也不要寫成:jsonData:{}。這會引起服務器端序列化錯誤。

  2.在Ext.Ajax.request({……})中加上一條:headers:{'Content-Type':'application/json; charset=utf-8'},不然,返回值是xml,而不是json字符串了。

 

  好了,這個通訊問題言盡於此,差很少了。

 

16.         extJs 2.0學習筆記(Ajax篇)

  一聽到Ajax,我與你們同樣,如雷貫耳,都說XXX Ajax框架,事實上,這一部份內容在ExtJs中是基礎中的基礎,就那個樣。這兒主要是討論一些資料、書本都不會涉及的領域。這些東西日常只能由本身摸索的。

  在此話題之先,先解決一個問題,如今用asp.net的人多了,可是,用asp.net ajax並不爽,可是asp.net ajax能直接調用webservice,看起來很眼讒,在extJs 2.1以前,是沒有辦法的,可是在2.1時,就能直接調用asp.net的webservice了。這個我實驗證實了。詳情點此處參見

  我總結一下用ExtJs訪問asp.net service的要點:

  1、Url的寫法:asmx地址+/+方法名

  2、method:post(也能夠是get,這樣,傳參數就得用params,用post的話呢就用jsonData)

  3、success:function(response,options),其中response.responseText若是是一個json字符串,那麼就要轉化,若是隻返回一個結果,那麼,所得的json對象默認有一個d成員,結果就在它裏面。

 

  上面這個問題實際上是主客交流的一種最簡單的狀況。然而,這些其實都不是重點,真正的關鍵以下:

  1、客戶端序列化爲json字符串後傳過去,服務器端怎樣取值

  2、服務器端把各類數據類型的數據是序列化成何種格式的,客戶端如何取。

  這兩個問題正是我將要研究的。內容將比較多,留在下文了。

17.         extJs 2.0學習筆記(Ext.data序論篇)

 昨天就說過了,ExtJs的UI部分不會花什麼時間了,是時候來研究一下Ext如何發送json數據,如何解析數據,如何顯示到咱們的widgets。如何管理異步請求。這些問題貌似都在Ext.data裏面。本人總結了一張UML圖。能夠獲得一個大概關係。

 

  其中,像Observable、DataReader、Record、SortTypes這四個類沒有標出父類,是由於它們繼承自Object,就省了。這個圖還清晰吧。

  由這個圖可知,ExtJs的數據處理包括三個部分:proxy、reader、store。至於connection、ajax,這個是對於XHR(XmlHttpRequest)的封裝。沒什麼好講的。關於XHR對象,本人前面做過一文,點此查閱!至於tree、node這兩個類與數據處理根本無關,Record至關於dotnet中的DataRow。表示一行記錄。咱們經過它來構造本身的記錄類。

  關於proxy、reader、store三者之間的關係,網上有少數資料講到,不過,人云亦云如何求得大道。我打算在解決了Connection、Ajax這兩個類後把它給研究透徹。


  這兩天極爲不爽,加上,愈來愈明白ExtJs的侷限性。把ExtJs真正應用於項目只怕仍是有麻煩的。不過,它很值得借鑑。不爲別的,只爲它優秀的理念、結構、UI。不得不使人佩服。不過,大量的js代碼,伴隨着需求的不斷變化,這些js代碼如何有效、方便地維護。這足以讓大部分流口水的人掉頭就走啊。沒想到又是一個有始無終啊。

18.         extJs 2.0學習筆記(Ext.Panel終結篇)

  怪不得我對Ext.Panel窮追猛打,前面已經寫過四篇針對它的文章了。不過。Ext.Panel的問題搞得差很少了。下面我貼出研究代碼,及效果圖。再解釋一下。這下圖文結合了。之後本身忘記了,看一下就明白了。

var panel1;

function newPanel1(){
 var config1={title:'
這是標題欄',
     width:300,
     height:300,
     floating:true,
     renderTo:Ext.getBody(),
     draggable:{
       insertProxy: false,
     
       onDrag : function(e){
        var pel = this.proxy.getEl();
        this.x = pel.getLeft(true);
        this.y = pel.getTop(true);
     
        var s = this.panel.getEl().shadow;
        if (s) {
         s.realign(this.x, this.y, pel.getWidth(), pel.getHeight());
        }
       },
     
       endDrag : function(e){
        this.panel.setPosition(this.x, this.y);
       }
     },
     tools:[{id:close,handler:function(event, toolEl, panel){panel.hide();}}],
     layout:'border',
     items: [{
       title: '
左邊欄',
       
region: 'west',
       split:true,
      
       height: 100,
       width:200,
       minSize: 75,
       maxSize: 250,
       margins: '5 0 5 5'
      },{
       title: '
中間主體部分',
       region:'center',
       margins:'5 5 5 0',
       split:true,

       minSize: 100,
      }],
     tbar:['
請輸入關鍵字:',
    {xtype:'textfield',width:80},'-',
    {text:'有種就點一下',handler:function(){alert("小子,你剛纔點了此按鈕!");}}],
     collapsible:true,
     shadow:false};
 
 panel1=new Ext.Panel(config1);
 panel1.setPosition(0,0);
 
 var resizer=new Ext.Resizable(panel1.getEl(),{handlers:'all'});
 resizer.on('resize',function(){panel1.updateBox(panel1.getSize());});
}

Ext.onReady(newPanel1);

  效果圖以下:

  

  看了上面的效果內心癢了吧。多漂亮啊。上面代碼的要點基本上在前面第四篇中講過了。也有一些事尚未來得及講。我分門別類的補充一下。

  1、Ext.Panel的組成

  Ext.Panel有五個部分,即:header、body、tbar、bbar、footer。在建立了panel的實例後,這五個對象就能被引用了,它們分別指向panel五個最重要的部分,tbar就是上面的工具欄,bbar就是下面的工具欄,footer就是放buttons的地方,它處於最下面。body就是整個panel的主體部分了。事實上,大夥只要用FireBug去看一下panel的dom結構就會發現,body外面還有一個div。這個div也有一個引用,叫:bwrap。不過,官方API文檔中沒有說起,想必是不想讓大夥去用它,怕之後會有變動。另外,tbar、bbar也是非文檔支持的。官方推薦使用:getTopToolbar()、getBottomToolbar(),用它們來得到上下兩個工具欄的引用,不過,這種方法只有在render後纔有效,有的兄弟使用了它,結果鳥結果都沒有。大惑、不解。若是要在render前操做工具欄,仍是要用tbar、bbar的。

  header、body、footer在官方文檔中都有說明,是Ext.Element類型。不用說了。

  基本上,有了這五個對象咱們能夠用它們來設置panel的各個部分了。

  2、如臂使指的操做Ext.Panel的每一寸土地

  有了上面五個對象,能搞定一些事情,可是,要說徹底控制Ext.Panel這頭驢還有所不及啊。這個問題通常人俺是不給他講的哦。哈哈哈。

  panel最外層的那個div,能夠用panel.el或panel.getEl()來得到它的Element引用。不少人不能理解,有了它有個屁用?一個Panel能玩出前面所說的這麼多的花樣足夠了。夠用了。然而永遠不要小看客戶的花花腸子。他們名堂多着吶。有了panel.el,能有什麼好處,嘿,曉得Ext.Fx不?Element能用到全部在它裏面定義的特效(animations)。而在Panel中,你去看一看官方API文檔,沒一字說起。也無法控制它搞點特效出來。你哪怕看了Ext.Panel也不會結果的。怎麼辦,得依靠Element了。我如今慶幸當初把Element的API研究得很完全。

  特效是一方面,另外,你去看一看Ext.Window的API文檔,會發現,它有alignTo、anchorTo的功能了,這但是好東西啊。可是,Ext.Panel沒有這個功能。我不用去看Ext.Window的代碼就曉得,這確定是取了panel.el來搞的,Element有alignTo、anchorTo這兩個API。例如:如何使Panel居中:panel.el.center()就好了。超強大啊。

  因此啊。有了panel.el這個引用,依託於ExtJs對dom的強大封裝結果所得的Element。咱們能夠作任何事(你能想到的、不能想到的)。

  另外,還有一個東西沒有被文檔公開:component.container。那指向component.el的父元素(div)。也是個Element引用。儘管咱們能用這個Element作事,可是,貌似尚未用到它的時候。機會很少。

  好了,這兒談到的都是關於控制Panel自身的架子的,說通俗點,架子是衣櫃,可是衣櫃裏面的衣服怎麼取出來呢?panel.el已經能很好地控制整個衣櫃,可是,衣服仍是一件都取不出來啊。有兄弟發火了,不是騙我嗎?這就是所謂的控制每一寸土地嗎?鑑於這個內容層次問題,把它放下一小節。

  3、取panel這個衣櫃裏的衣服

  這個問題是我老劉的獨門武學,我敢保證曉得這事的人很少。曉得這事的人一定是用FireBug研究過panel的dom結構的人或者是研究過layout的源代碼的人。這種人很少啊。大夥都本着能用就行的想法啊。不吹了。還記得Ext.Panel的API文檔上面一句話:

  If this Panel is intended to be used as the host of a Layout (See layout then the body Element must not be loaded or changed - it is under the control of the Panel's Layout.

  這是關於body的說明中的一句話,說得好,精闢,它說,若是你想在panel中用佈局類,那麼你不得以任意方式來修改body。不要想着用panel.body.update(xxxx)來幹活了。由於文檔說了:it is under the control of the Panel's Layout。它正處在panel的layout的控制之下,嘿,這是個人layout的地盤,你就不要來整蠱了。

  就是說,要麼用body,要麼就只能用layout。雙方是排斥的,這不難理解。我一個小時前,在FireBug寫了條命令語句:

  console.dir(panel1);

  這個東西諸位不曉得的話,那意味着你要去研究一下FireBug了。它的做用是把panel1的全部成員都輸出到控制檯窗口中。我看了輸出的結果,發現:panel有一個layout的成員,如圖:

 

  可能圖看不清,諸位點一下看原圖吧。我發現了個有趣的結果:

  layout有兩個成員:center、west。

  這兒我用的是border layout。由於這兒我只用到兩個區,因此只有center、west。若是五個區都有了,推理得:那就會有五個了:west/east/center/south/north。原來,borderlayout是有五個這樣的引用,可供咱們來控制這五個區域。

  哈哈哈,有了這五個對象,就至關於衣櫃中有五個格子,個人手又能伸進更細緻的地方了。

  依此推理(我還沒來得及研究layout的源代碼)可知,咱們是有能力利用layout的提供的一些接口來控制body內部的細節的。

  剛纔靈光一閃,API文檔中,提到兩個類:

  Ext.layout.BorderLayout.Region

  Ext.layout.BorderLayout.SplitRegion

  我在FireBug控制檯寫下以下實驗代碼:

  panel1.layout.west instanceof Ext.layout.BorderLayout.SplitRegion

  結果爲:true

  嘿,可見,borderLayout是內部是以區域對象來進行控制的。不過,在BorderLayout的官方文檔中沒有對此說起,Ext.layout.BorderLayout.Region這兩個類的文檔卻是有的。

  總結經驗:layout不只僅只是設計時佈局,也許它提供給咱們一些有意思的接口啊,只是,這個可能須要本身去研究、琢磨。

   4、關於BorderLayout的釘子

  再次吹牛,這個問題老實說,在API上面是沒有講到的。就是在定義borderLayout的各個區域時,注意要設幾個量:region/split/margins/cmargins。這個用法應當不用講了,本身瞎琢磨去吧。那個cmargins的用法我尚未摸明白。網上關於這方面的細節資料太少了,一個勁地在那兒打屁。難有實質性內容,真是的。

  5、關於Toolbar的事

  關於工具欄類我如今尚未來得及研究。不過初步用法仍是要說一下:

  'xxxxx'至關於{xtype:'tbtext',text:'xxxxx'}

  '-'至關於{xtype:'tbseparator'}

  也是個簡寫法。

  6、關於resize功能與Ext.Panel的一些衝突

  pinned:true不能設、shadow必須爲false。否則衝突起來的效果……描述出來。這個是我我的摸索的結果。不想描述。試一試就出來了。

 

  至此,Ext.Panel總算終結了。我等不及了,得研究一下Ext.data中的東西了。關於UI,一個理,把Element、Component、Observable、BoxComponent好好的研究一把,UI就舉一反三了。

  伯平經驗:要研究ExtJs,先把JavaScript+DOM搞得爐火純青了再說(比欲練此功,揮刀自宮容易多了吧!)

  祝諸君學有所成。

19.         extJs 2.0學習筆記(事件註冊總結篇)

原本,我也沒把這檔子事放在眼裏,由於簡單,例如:

  Ext.get("elem").on("click",{fn:function(){alert("此元素被單擊了!");}};

  這樣的代碼誰不會寫啊。一個on就告終了。可是,今天,我在研究Ext.Panel的tbar時,發現,那現工具欄按鈕的事件註冊不同:

  元素註冊、組件註冊都是:{fn:……}

  工具欄按鈕的事件註冊:{handler:……}

  嘿,我就在想,爲何Ext的做者就不統一一下呢,都是fn多好。免得我分心了。一不當心準搞錯了。還好,不是fn就是handler,凡是工具欄上面的東西註冊事件,通常都是用handler,日常組件註冊事件通通都用fn。

  關於組件的事件註冊,通常都是建立時就定義好,而不是建立後再來on。因此,用extjs寫程序,經常看到Ext.onReady裏面嵌套了無數層,items裏面還有items,items裏面還有listeners。而後listeners裏面定義事件處理器。這樣,代碼就比較難看了。有人說:extJs寫的代碼莫名其妙。呵呵,可見大夥不大喜歡這種寫法啊。

  關於事件處理,我把Element的API文檔翻譯了一下。事實上事件註冊都是創建在Element之上的。

  1、元素的事件註冊
  on( String eventName, Function fn, [Object scope], [Object options] ) : void
  其中:
    eventName:String
  事件名稱
  fn:Function
    事件處理函數,它有三個參數
    evt:EventObject 事件對象
    t:Element    事件發生的目標Element,注意:它將被delegate選項所篩選(頗有用)。
    o:Object     addListener函數傳入的options對象。

  scope:Object 範圍
  options:Object 選項參數
  一個包含了事件配置屬性的對象,它可能包括以下屬性:
  scope {Object} :它表示事件處理函數的執行範圍,即處理函數時面的this的上下文。
  delegate {String} :一個簡單的selector,用於過濾target或者找target的子孫。
  stopEvent {Boolean} :爲true就中止事件,即中止事件的傳播和阻止默認行爲。
  preventDefault {Boolean} :阻止默認行爲
  stopPropagation {Boolean}:中止事件的傳播
  normalized {Boolean} : 爲false的話就傳遞一個瀏覽器的原裝事件對象給函數,而不是Ext.EventObject。
  delay {Number} : 這個值表示事件發生後多少毫秒,事件處理函數才被執行。
  single {Boolean} : 爲真的話呢就表示這個事件處理器只執行一次,以後自刪除。
  buffer {Number} :它的做用就是執行緩衝,有時候,用戶點按鈕作死的點,一秒點它幾十次,難道讓事件處理函數執行幾十次嗎?其實,用戶並不必定是執行屢次。若是真的就這樣老老實實執行了,極可能就壞事了,作了無用功。
  這個值表示,在事件發生後,事件處理函數將放到Ext.util.DelayedTask中去計劃執行,多少毫秒以內,若是再次發生同一事件,那麼,這一事件將覆蓋原來的事件。只執行後面那一次,固然,那個緩衝時間也在後一次時被刷新。


  組合Options中的選項
  在下面的例子中,on這種快捷的方式比冗長的addListener好用的多了。二者是等價的。使用Options做參數,它能組合多種不一樣的事件處理器:
  一個普通的,能延時執行的,只執行一次的,能自動中止事件的,還有一個自定義參數(forumId)在options對象,這個Options對象是合法的。代碼以下:

el.on('click', this.onClick, this, {
    single: true,
    delay: 100,
    stopEvent : true,
    forumId: 4
});

  一次註冊多個事件
  這個方法也容許只傳一個config,可是一個config中包含多個事件處理信息。代碼以下:
el.on({
    'click' : {
        fn: this.onClick,
        scope: this,
        delay: 100
    },
    'mouseover' : {
        fn: this.onMouseOver,
        scope: this
    },
    'mouseout' : {
        fn: this.onMouseOut,
        scope: this
    }
});
或者是如下簡捷語法:
el.on({
    'click' : this.onClick,
    'mouseover' : this.onMouseOver,
    'mouseout' : this.onMouseOut,
    scope: this
});

 

  上面是通常事件,還有快捷鍵註冊的問題,事實上,Ext對快捷鍵這個功能的封裝其實就是對keypress這個事件的改造。怎樣定義快捷鍵映射呢,Ext.Element.addKeyMap(config)。因此,問題的重心又到了config這個東西了。我找到Ext.KeyMap這個類,研究一下:
  config的屬性有:
  key:number/string/Array,例如:
    key: 13, // or Ext.EventObject.ENTER
    key: "a\r\n\t"
    key: [10,13],    //回車鍵被按了
    key: "abc"     //按了a或b或c
    key: "\t"
    由上可知,能夠是設成單個按鍵,也但是多個按鍵,但是ascii碼,也能夠是那個字母。
  fn:Function
    相關聯的處理函數,例如:
    fn: function(){ alert("Return was pressed"); }
  ctrl:Boolean
  shift:Boolean
  Alt:Boolean
  scope:Object

  

  總結上面,Element中的事件註冊方法都差很少。

 

  2、關於組件上的事件註冊
  組件的事件註冊有它的特色了,儘管本質上仍是on、un。若是用on、un,它的語法跟Element的語同樣,沒什麼差異,關鍵是,組件容許在建立時的config中用listeners:{xxx:{},yyyy:{}}的形式的註冊事件。不過,listeners裏面的寫法跟on的組合寫法是同樣的。這個我研究了。例如:
  listeners:{'select': {fn:this.sortImages, scope:this}}
  仍是:事件名:options
  
  組件沒有什麼快捷鍵關聯的功能,不過,能經過元素的快捷鍵註冊功能來獲得。這個沒什麼問題。Ext.Window

有一個Keys config的屬性,用它能夠定義快捷鍵。  

 

20.         extJs 2.0學習筆記(Ext.Panel篇一)

  老實不客氣的說:沒有Panel,就沒有extjs的盛名。那些最多見的UI組件都是繼承自它。暴爽的東西啊。我就在想,這麼好的東西怎麼會出現得這麼晚呢?

  在這一篇中,將詳細講一講Ext.Panel的方方面面。

  如今遇到了一些問題:

  1、顯示的問題

  事實上,這個問題是全部組件的問題,凡是從Ext.Component繼承的類都面臨這個問題。

  例如,我寫了一行這樣的代碼,可是沒有任何結果:

  var panel=new Ext.Panel({width:300,height:300,title:'標題欄'});

  這是什麼緣由呢?

  if(this.applyTo){
    this.applyToMarkup(this.applyTo);
    delete this.applyTo;
  }else if(this.renderTo){
    this.render(this.renderTo);
    delete this.renderTo;
  }

  這幾行代碼是寫在Ext.Component的構造函數中的。它標示若是applyTo、renderTo有值,就會在對象建立的時候直接呈現,若是這兩值都沒有,那就只能手工調用render函數了。

  然而這有一個問題,applyTo與renderTo倒底有什麼區別,它們取值類型能夠是哪些呢?看代碼。

  applyTo的狀況依賴於this.applyToMarkup來實現呈現。找到它的代碼:

  applyToMarkup : function(el){
   this.allowDomMove = false;
   this.el = Ext.get(el);
   this.render(this.el.dom.parentNode);
  }

  而renderTo的狀況是直接依賴於this.render(this.renderTo)的。這二者的差異很明顯了,可是,這個問題到目前還不能說清楚,我發現,Ext.Panel最後生成的代碼以下:

  <div id="panel2" class="x-panel" style="width: 300px;">
    <div id="ext-gen14" class="x-panel-header x-unselectable" style="-moz-user-select: none; cursor: move;">
      <span id="ext-gen18" class="x-panel-header-text">這是標題欄</span>
    </div>
    <div id="ext-gen15" class="x-panel-bwrap">
      <div id="ext-gen16" class="x-panel-body" style="width: 298px; height: 273px;">這是面板的內容!!!</div>
    </div>
  </div>

  由上代碼可知,panel的代碼老是外面一個容器:x-panel,而後裏面幾個,這兒是:x-panel-header、x-panel-bwrap。如今能夠說一說renderTo與appplyTo的區別了。

  renderTo與applyTo的傳入參數的數據類型與Ext.get的參數類型同樣,但是dom、string、Element。它們最大的不一樣在於容器,這個容器不是指x-panel所對應的元素,而是指x-panel所對應元素的父元素。由源代碼可知:

  當爲applyTo時,它調用render(this.el.dom.parentNode);可見,x-panel的容器爲applyTo對應元素的父元素。也便是applyTo事實上就是x-panel。而renderTo時,renderTo所對應元素是x-panel的容器。如何驗證這個問題呢?請到FireBug中看一看就曉得了。

  上面說了一大通,我再總結一下:

  renderTo:對應x-panel所在div的父元素;

  applyTo:對應x-panel所在div自己。

  2、Ext.Component的幾個極其重要的成員

  component.el:在panel中至關於x-panel所對應的div。它表示Component所對應的最外層html元素。

  component.id:在panel中至關於x-panel所對應的div的id,若是x-panel所在div沒有id,那麼就本身分配一個。

  component.container:它在panel中至關於x-panel所在div的父元素。即x-panel的容器。也便是:component的容器。

  若是沒有分清楚這個問題,那麼下面代碼會產生問題:

  var p=new Ext.Panel({title:'my title',width:300,height:300,renderTo:'panel1'});

  console.info(Ext.getCmp('panel1'));

  結果如何呢?undefined!!

  爲何是這樣呢,由於,getCmp用的id便是component.id。而這個id對應的是x-panel所在元素的id或者自由分配的。而renderTo對應的元素不是x-panel。而是x-panel的父親。這個問題極容易搞錯。

  這兒的兩個問題其實都是Ext.Component那裏的。下一篇正式研究一下Ext.Panel的API了。

 

21.         extJs 2.0學習筆記(Ext.Panel篇二)

  這一篇翻譯自extJs 2.0官方文檔。這篇是關於config的。

  我在網上查了好久,關於ExtJscore部分的中文文檔仍是有很多,可是關於panelwindow這些呢就好像不大齊全,並且,在js堂,它的文檔翻譯還在1.1。因此呢想翻譯出來,之後你們也好查閱。

  本人js水平、英文水平都有限,還好,經過看源代碼兩相印證,終於仍是搞出來了。歡迎各位提出寶貴的意見。事實上,只要搞定了panel,其也組件的config差很少。大同小異。嘿嘿。一通百通啊。

activeItem : String/Number
用於設置當前活動的子組件,取值爲此子組件的序號或者是id。可是它只能應用於那種一次只能顯示一個子組件的佈局類,例如:Ext.layout.Accordion, Ext.layout.CardLayout和Ext.layout.FitLayout。

allowDomMove;Boolean
是否能夠在組件呈現的過程當中移動組件的dom節點。默認值爲true。

animCollapse : Boolean
設置是否在面板收縮時起用動畫,若是Ext.Fx有效(被包含進來)則默認爲true,不然爲false。

applyTo:Mixed
x-panel對應的div的id。


autoDestroy : Boolean
若是要把一個子組件從panel中移除且此值爲true,則在移除的過程當中自動會銷燬此組件,返之,則不會,必需要手工銷燬,默認值爲true。


autoHeight : Boolean
若是爲true,把this.el.dom.style.height='auto'。默認值爲false。

autoScroll : Boolean
爲true時,則把this.body.dom.style.overflow='auto'。默認值爲false。

autoShow : Boolean
爲true時,檢查組件是否被設成隱藏,若是有,則移除這個效果。

autoWidth : Boolean
同autoHeight同樣。。

baseCls : String
this.baseCls的class(默認值爲'x-panel')

bbar : Object/Array
面板底部的工具欄。它但是一個Ext.Toolbar對象,也能夠是一個toolbar的config對象,或者是一個要加入到工具欄的按鈕的config的數組。注意:這個屬性在render後就無效了,若是要在render後使用它,請使用 getBottomToolbar得到引用。

bodyBorder : Boolean
若是爲true則爲this.el對應的元素顯示邊框,默認值爲true。這隻在border==true時纔有效。若是border==true且bodyBorder==false,那麼將顯示1px的inset邊框。給予this.el inset的效果。

bodyStyle : String/Object/Function
要應用到this.el上的css class。它的格式需求與Ext.Element.applyStyle同樣,默認值爲null。

border : Boolean
也是設this.body的邊框的,默認值爲true,此時,默認狀況下邊框爲2px。固然,它還會被bodyBorder影響。

buttonAlign : String
加入到面板中的按鈕的對齊方式,合法值爲:'right','left','cente',默認值爲'right'。

buttons : Array
Ext.Button的config數組,用於加入按鈕到面板的footer中。

cls : String
this.el的class。

collapseFirst : Boolean
當顯示title bar時,是否總把收縮、展開按鈕放在全部其餘按鈕的前面。默認值爲true。

collapsed : Boolean
在呈現時,是收縮仍是展開。爲true則收縮,默認值爲false。


collapsedCls : String
當面板處於收縮狀態時,this.el所對應的class,默認值爲'x-panel-collapsed'。

collapsible : Boolean
此面板是否可收縮或者說是否能顯示收縮、伸展按鈕。真爲顯示。默認值爲false。

contentEl : String
一個已存在的dom的id。做用是用於在afterRender後把它this.body.dom.appendChild掉。默認值爲''。

ctCls : String
設this.container的class。

defaultType : String
當在構造函數中用items填加新成員時,若是沒有設xType,那麼就會以這個默認類型爲xType加入組件。默認值爲'panel'。


defaults : Object
加入此組件的全部子組件的默認config。若是這些加入的子組件設了config的話就以新設的爲準。例如:{bodyStyle:'padding:15px'}。


disabledClass : String
當組件被設成disabled時的css,默認值爲:"x-item-disabled"。

draggable : Boolean
是否能被拖動。默認值爲false。固然也能夠是一個Ext.Panel.DD config。Ext.Panel.DD是一個internal但非公開的類(我沒有找到它的源代碼),它的做用是移動一個proxy元素(Element)以代替本應跟隨鼠標移動的panel.el。可是它在拖動過程當中、放下時不提供任何其餘動做,也就是說,若是你不做處理的話,鼠標一鬆,panel仍然在老地方。它是Ext.dd.DragSource的子類,因此,必須經過實現Ext.dd.DragDrop的方法來產生動做。示例代碼以下:

new Ext.Panel({
    title: 'Drag me',
    x: 100,
    y: 100,
    renderTo: Ext.getBody(),
    floating: true,
    frame: true,
    width: 400,
    height: 200,
    draggable: {
//      Config option of Ext.Panel.DD class.
//      It's a floating Panel, so do not show a placeholder proxy in the original position.
        insertProxy: false,

//      Called for each mousemove event while dragging the DD object.
        onDrag : function(e){
//          Record the x,y position of the drag proxy so that we can
//          position the Panel at end of drag.
            var pel = this.proxy.getEl();
            this.x = pel.getLeft(true);
            this.y = pel.getTop(true);

//          Keep the Shadow aligned if there is one.
            var s = this.panel.getEl().shadow;
            if (s) {
                s.realign(this.x, this.y, pel.getWidth(), pel.getHeight());
            }
        },

//      Called on the mouseup event.
        endDrag : function(e){
            this.panel.setPosition(this.x, this.y);
        }
    }
}).show();

 

elements : String
一個panel有五個部分:header、tbar、body、bbar、footer。elements就是保存當前panel包含了幾個部分,例如,一個panel有header、body,那麼:element=='body,header',默認值爲:'body'。


floating : Boolean
爲true的話,它會使panel.el.style.position=absolute。而且,默認狀況下帶有shimming和shadow。爲false則不改變原有顯示方式。
注意:把floating設爲true會致使panel以offsets大量負偏移的方式隱藏。這個諸 位試一下就曉得了。因此呢,若是設了floating=true。那麼,你render後最好還要setPostion(x,y)一下。固然若是你讓面板浮動,也要把width設成一個固定值,否則,它會向右擴展到viewport的邊緣。


footer : Boolean
爲true則明確地建立footer,爲false就不建立,默認狀況下,若是對footer沒有什麼特殊的,那麼當一個或多個按鈕被加到footer上面時,footer會被自動建立。


frame : Boolean
爲true的話呢就就在panel外面加上自定義的圓角邊框,爲false的話就是1px寬的長方形邊框。


header : Boolean
爲true時header被建立,反之不被建立,默認狀況下,當header不處於特殊狀況時,若是title被設置,它會被自動建立,不然不會被建立,如是果title被設置,可是header爲false,那麼header也不會被建立。


headerAsText : Boolean
爲真是在header中顯示title,爲假時隱藏它。默認值爲true.


height : Number
panel的高度,默認爲auto。


hideBorders : Boolean
爲true時,隱藏panel的全部子組件的邊框,爲false則尊從子組件原有邊框設置。

hideCollapseTool : Boolean
當collapsible=true且hideCollapseTool=true時,則隱藏控制收縮、伸展的那個按鈕,爲false時就顯示它,默認值爲false。


hideMode : String
隱藏模式,有三種: "visibility" (css visibility), "offsets" (negative offset position) and "display" (css display) - defaults to "display"。

hideParent : Boolean
用於設置是否隱藏組件的容器,即component.container。

html : String/Object
一個html碎片,或者是知足DomHelper語法的object,它用於設置panel的body部分的內容。默認值爲''。

iconCls : String
用於設置header上的圖標的class。例如:.my-icon { background: url(../images/my-icon.gif) 0 6px no-repeat !important;}


id : String
一個爲component統一分配的id值。默認值爲panel.el.id。

items : Mixed
單個成員或一個子組件的數組。每一個成員均可以是任何從Ext.Component繼承的object。

它的成員能夠是component的引用,這樣就會立刻render,也能夠是component的config。這時就會lazy render。固然,在config中,要注意加上xtype。這個東西不用講了吧。

關於xtype的全部取值狀況,請見Ext.Component.xtype的config說明。裏面有講到。關於它的值,其實不少例子上都有,若是傳一個成員,則像:items:{……},傳多個的話呢,就像:[{……},{……}]。

keys : Object/Array
一個keyMap config object。用於設置快捷鍵的。默認值爲null。


layout : String
設置panel.container的佈局。若是沒有設置,那麼默認爲Ext.layout.ContainerLayout,合法的值有:absolute, accordion, anchor, border, card, column, fit, form和table。若是要設置佈局的細節,則要用到layoutConfig了。


layoutConfig : Object
用於設置佈局細節的,當layout有合法設置時它纔有效果。若是要知道關於這個config的設置細節,請見各佈局類:
Ext.layout.Absolute
Ext.layout.Accordion
Ext.layout.AnchorLayout
Ext.layout.BorderLayout
Ext.layout.CardLayout
Ext.layout.ColumnLayout
Ext.layout.FitLayout
Ext.layout.FormLayou
Ext.layout.TableLayout

listeners : Object
一個config對象用於包含一個或多個事件handler,它被addListener使用來註冊事件。

maskDisabled : Boolean
是否在panel.disabled的時候顯示mask。爲true顯示。反之不顯示。
默認狀況下,panel哪怕在disabled時,它的子元素也顯示得很正常,用戶根本不知道這個panel被禁用了,這給用戶帶來困擾,可是,有了mask,用戶就能獲得提示,哦,這個panel是不可用的,被禁用了。這給用戶帶來了新的體驗。


minButtonWidth : Number
panel上全部按鈕的最小寬度,單位是px。

monitorResize : Boolean
爲true時,它自動監控window的resize事件,而且讓viewport所以而變化。這個東西的經典應用就是爲layout服務,而不用咱們手工去調整某些組件的大小來適應窗口大小的變化。


overCls : String
當鼠標放到panel.el上面時的class。最爽的是,當鼠標out時,它會被自動刪除,從而產生hover效果。


pageX : Number
組件相對於頁面的x座標

pageY : Number
組件相對於頁面的y座標

plugins : Object/Array
一個對象或對象數組,它爲component提供自定義的功能。每一個對象都是一個插件的引用,固然,前提是這個插件定義了init方法,在component初始化時,這個init方法將被調用。沒用着。不說了。難翻譯啊。

renderTo : Mixed
Ext.get(panel.renderTo)就是panel.container。用語言說不清楚,這樣直接了當。

shadow : Boolean/String
爲true就給panel顯示一個陰影,爲false不顯示。固然,也可設置成爲shadow的類型,詳情見Ext.Shadow、Ext.Shadow.mode。注意,這個選項只有在floating = true時才發生做用。

shadowOffset : Number
陰影偏移,默認值爲4,只有在floating = true時才發生做用。

shim : Boolean
是否爲組件建立shim,什麼是shim呢?存在這樣的狀況,用div作的菜單,可是,好死不死有個applet或flash蓋在上面的話,那菜單就會被蓋在下面。這件事情曾經一度讓b/s人員鬱悶,ext提供一個通用的解決方案,在要避免這個問題的組件的同一位置建立一個與它大小同樣的iframe,且使得這個組件的z-index大於iframe。因爲iframe不會被其餘東西遮住,因此,z-index在iframe之上的東西也不會被遮,iframe至關於個墊子,把咱們要用的東西墊高了,而shim英語裏面也是薄墊片的意思。高呼extjs萬歲。固然,iframe的src必須爲''。

stateEvents : Array
事件數組,當這此事件觸發時,組件狀態被保存。

stateId : String
用於管理組件狀態的id,默認值爲組件的id.

stateful : Boolean
一個標誌,它表示組件在建立時是否從某個地方加載組件狀態。哪些屬性能做爲狀態保存呢?只有internal屬性能夠。
爲了讓組件狀態能保存,組件狀態管理器提供者必須實現Ext.state.Provider,也就是要實重寫它的set、get方法以保存/重讀鍵/值對,一個內鍵的提供者是: Ext.state.CookieProvider。

爲當前頁面設置狀態提供者的方法以下:
Ext.state.Manager.setProvider(new Ext.state.CookieProvider());

組件試圖在stateEvents裏面配置了事件時保存狀態。你能夠本身寫點代碼進行一處理,如在:beforestaterestore, staterestore, beforestatesave和statesave事件的處理代碼中。

style : String
一個應用於panel.el上的樣式,語法必須知足Ext.Element.applyStyles的接口。


tabTip : String
當panel是Ext.TabPanel中的一頁時,爲這個panel設tooltips的。不過,在render以前得先調用Ext.QuickTips.init()初始化一下。

tbar : Object/Array
panel頂部的工具欄,它能夠是一個Ext.Toolbar,也能夠是一個按鈕數組或一個按鈕的config。注意:在render以後,這個引用就沒用了。若是要處理它請使用getTopToolbar。

title : String
顯示在panel的header中的標題,當title被設置時,header就會被建立,除非header被設成false。若是你須要title,但不是在panel建立時,而是在以後的某個時刻,這時你須要爲title設置一個非空值(如一個空格)或者是把header設爲true。這樣,panel在建立時纔會建立header,否則,header將不會被建立。

titleCollapse : Boolean
當collapsible = true且titleCollapse=true時,用戶點擊panel標題欄的任意一處都會產生摺疊/伸展效果,不然則只能經過單擊那個按鈕(上文有講到)來產生這個效果了。


tools : Array
一個工具欄按鈕數組,這個工具欄非同通常哦,不是tbar,也不是bbar,而是header上的標題欄,header上的標題欄是怎樣的概念?你看到的panel的關閉按鈕這個鈕,超爽吧。每一個工具欄元素以一個Element引用的方式向開發人員公開,經過
   tools.<tool-type>的方式引用。暴爽。
每一個工具欄成員的config要包含下面屬性:
id:string
  必需的,工具欄按鈕的類型,可取值以下:

toggle (Created by default when collapsible is true)
close
minimize
maximize
restore
gear
pin
unpin
right
left
up
down
refresh
minus
plus
help
search
save
print

handler : Function
必需,當按鈕被單擊時被執行。它的參數說明以下:
  event:Ext.EventObject
  toolel:Ext.Element
  Panel : Ext.Panel宿主panel

scope : Object
qtip:String/Object
一個tips字符串或者是tips config,用於Ext.QuickTip.register.

hidden : Boolean
on : Object
自定義事件處理器的config,爲addListener所用。


示例以下:
tools:[{
    id:'refresh',
    qtip: 'Refresh form Data',
    // hidden:true,
    handler: function(event, toolEl, panel){
        // refresh logic
    }
}]
  注意:除了toggle以外,其餘工具欄成員都只是提供一個可視化的圖標,沒有任何功能,因此,若是你要加入它們,得本身寫處理函數。


width : Number
component的寬度,單位用px,默認值爲:auto。

x : Number
得到組件的x,至關於panel.el.style.left

xtype : String
這個東西不用說了,見Ext.Component的config裏面的xtype。

y : Number
與x同理。

 

22.         extJs 2.0學習筆記(Ext.Panel篇三)

  上一篇中把panel的config部分的文檔翻譯了一下,事實上,好多東西都加上了我本身的見解,也不能說徹底是翻譯。真是個苦差使啊。這一次主要是來研究一下Ext.Panel的屬性、函數。

屬性:

body : Ext.Element
它是指向panel的body的Element引用。它被用於包含html內容。能夠經過html config,或者是autoLoad config,又或者是經過panel的Updater來設置內容。此屬性只讀。
若是此屬性被任何方法加載了html內容,那麼這個panel就不能經過佈局類來控制佈局了。
若是這個panel已被佈局類所管理,那麼就不能對body進行任何改動,或加載什麼內容。由於它正處於panel的佈局管理類的控制之下。

buttons : Array
panel的button數組,它經過buttons config建立,只讀。

dd : Ext.dd.DragSource.
若是此panel配置了draggable屬性,這個屬性將包含一個Ext.dd.DragSource的實例。開發人員經過必須提供對Ext.dd.DragSource的抽象方法的實現來達到支持drag/drop動做的目的。詳情可見draggable。

disabled : Boolean
若是組件是disabled,那麼它爲true。只讀。


footer : Ext.Element
指向panel footer的Element的引用。只讀。它用於存放panel的buttons所定義的按鈕。通常不要用它來放按鈕。


header : Ext.Element
指向panel header的Element的引用。只讀。這個元素用於存放title和tools。

hidden : Boolean
若是組件是隱藏的,那麼它爲true,只讀。


initialConfig : Object
組件的config。只讀。

items : MixedCollection
panel中的子組件的集合。

ownerCt : Ext.Container
組件的父組件,默認值爲undefined,而且在加入到一個容器中時會被自動設置。只讀。


rendered : Boolean
組件是否已經被呈現。。

 

公共方法:
Panel( Object config )

addButton( String/Object config, Function handler, Object scope ) : Ext.Button
config:若是是個字符串就被看成是按鈕的text,若是是個object,那麼它被看成config了。
handler:被按鈕的Ext.Button.click調用。
scope:範圍。
返回:被加入的按鈕的實例。


collapse( Boolean animate ) : Ext.Panel
收縮面板


destroy() : void
看一下源碼就知道,把組件掛接的事件、子元素什麼的所有移除、delete。在什麼Ext.ComponentMgr裏面註冊的東西也註銷掉。


disable() : Ext.Component
沒懸念。。使組件不可用。至關於大夥在dotnet中用得很爽的enabled。


doLayout( [Boolean shallow] ) : void
強制容器從新計算佈局,就是刷新佈局啦。它的做用就是當在render以後加入了一個組件時,這時就須要調用它來刷新一下了。又或者是改變了子組件的大小、位置,這時也要刷新一下。


expand( Boolean animate ) : Ext.Panel
伸展panel。


getBottomToolbar() : Ext.Toolbar
得到panel的bbar。

 

getFrameHeight() : Number
它的高度包括:header,tbar,bbar,footer,可是不包括body。單位是像素(px)。若是要得到body的高度,請使用getInnerHeight。


getFrameWidth() : Number
得到panel的邊框寬度。固然是不包括body的寬度的,要得到body的寬度用getInnerWidth。

getId() : String
得到組件的id。


getInnerHeight() : Number
僅僅返回panel.body的高度。不包括其他四個部分。


getInnerWidth() : Number
僅僅返回panel.body的寬度。

getTopToolbar() : Ext.Toolbar
取得tbar的引用。

getUpdater() : Ext.Updater
經過Ext.Updater得到此panel的updater,有了它就能經過ajax更新panel.body了。

load( Object/String/Function config ) : Ext.Panel
經過一個XHR(XmlHttpRequest)調用立刻加載內容。
示例代碼以下:
panel.load({
    url: "your-url.php",
    params: {param1: "foo", param2: "bar"}, //或者是url編碼的字符串
    callback: yourFunction,
    scope: yourObject,
    discardUrl: false,
    nocache: false,
    text: "Loading...",
    timeout: 30,
    scripts: false
});

這裏面,惟一一個必須的屬性就是url。


setIconClass( String cls ) : void
用於設置panel上的全部的icon的樣式,若是哪一個圖標設置了樣式,都會被它所替代。


toggleCollapse( Boolean animate ) : Ext.Panel
若是處理收縮狀態就伸展,若是是伸展就收縮。總之與當前狀態相反。


事件呢就不用了。


這個仍是蠻容易的,個把小時搞定了。

 

23.         extJs 2.0學習筆記(Ext.Panel篇四)

  我剛纔禁不住誘惑去看了一下Ext.Window的API文檔,發現只是比Panel多了點什麼最大化、最小化、關閉、置前、置後、動畫引起目標設置、可調整大小這些功能。像什麼標題欄、工具欄之類的東西在Ext.Panel早就封裝好了。搞定了Ext.Panel終於能夠悶聲發大財羅。哈哈哈。

  這一文主要總結一下,panel的常見用法。

  1、使Panel的標題欄隱藏

  這是常有的事,經常,一個欄目並不須要標題。有什麼辦法呢,建立時config中加上:header:false。就ok了。

  2、如何使Panel能被拖動

  確保config中以下設置:

 var config1={title:'這是標題欄',
     width:300,
     height:300,
     header:false,
     floating:true,
     renderTo:Ext.getBody(),
     draggable:{
   insertProxy: false,
     
   onDrag : function(e){
   var pel = this.proxy.getEl();
   this.x = pel.getLeft(true);
   this.y = pel.getTop(true);
     
   var s = this.panel.getEl().shadow;
   if (s) {
     s.realign(this.x, this.y, pel.getWidth(), pel.getHeight());
   }
       },
     
  endDrag : function(e){
    this.panel.setPosition(this.x, this.y);
       }
     },

     html:'這是面板的內容!!!',
     layout:'fit',
     collapsible:true};

  好了,關鍵就是上面紅色部分了,由前面的文檔可知:Ext.Panel.DD這個類只是提供移動Proxy元素的效果,鼠標一鬆,panel仍在老地方,因此得寫代碼實現。關於Ext.Panel.DD,這個類是非公開的,我在源代碼中也沒有找到。不曉得放在哪。最後,我只得打開FireFox+FireBug纔看到它裏面的東西。

  爲何必定要floating:true呢?緣由很簡單,要能拖動,那麼這個div就是absolute的,而一個panel.el默認不會是absolute。因此非得設成floating,以讓它能浮動。

  3、如何有Panel能摺疊、展開效果。

  這個很簡單,panel在title tools中提供一個toggle的工具,就是用它幹這事的,不過,默認狀況下,panel的這個功能是被關閉的。panel還提供一個功能,單擊title的任意一處都會產生toggle collapse效果。相關的config屬性我提出來以下:

  animCollapse : Boolean

  collapseFirst : Boolean

  collapsed : Boolean

  collapsedCls : String

  collapsible : Boolean  //事實上,把它設成trueok了,其它幾個能夠不設置。

  titleCollapse : Boolean

  關於它們的使用說明請參見前面的API文檔。不過,單看名字應當就曉得用了,取名很直觀。

  4、怎樣爲panel設置title tools

  就是怎樣爲Panel的標題欄添加按鈕,這個容器,在config中相似以下代碼便可:

  tools:[{id:close,handler:function(event, toolEl, panel){panel.hide();}}],

  格式通常是:tools:[{……},{……},{……}]

  5、怎樣顯示、隱藏panel

  這個很容易,panel.show()/hide()就好了。可是,若是floating:true的話,那就麻煩了,show都顯示不了,我在FireBug中一看,panel.el.dom.style.left="-10000px"。這固然是顯示不出來的。因此,你show了還要setPosition一下。這才行了。

  6、爲panel添加子組件

  簡單,在config中加items屬性,相似於以下代碼:

  items:[{id:'win1',xtype:'window',title:'title',height:100,width:100}],

  格式通常是:items:[{……},{……},{……}]

  若是在定義時,沒有設置xtype,則子組件建立是xtype取defaultType的值。像上面,因爲window建立後是不顯示的,因此,只得show出來。因此,我在定義時給它一個id。這樣在Ext.onReady()中就能夠:Ext.getCmp("win1").show()。嘿,就出來了。其餘組件的加入相似。一個{}是一個組件。

  像上面那樣的叫惰性呈現,還有一種寫法是:items:[new XXX(config)]。這樣的定義會在組件建立時直接呈現。

  7、爲panel設置佈局

  這個是關鍵了。就是要設layout、layoutConfig。這個要詳細的講一下。日常要用嘛。這兒用BorderLayout的文檔上的代碼爲例:

     layout:'border',
     items: [{
       title: 'South Panel',
       region: 'south',
       height: 100,
       minSize: 75,
       maxSize: 250,
       margins: '0 5 5 5'
      },{
       title: 'West Panel',
       region:'west',
       margins: '5 0 0 5',
       cmargins: '5 5 0 5',
       width: 200,
       minSize: 100,
       maxSize: 300
      },{
       title: 'Main Content',
       region:'center',
       margins: '5 5 0 0'
      }],

  其實,佈局類的api接口很簡單,使用也不復雜。果真是把swing的那一套學過來了。

  Ext.layout.BorderLayout是一個比較特殊的佈局類,它沒有什麼正兒八經的config,不像Panel它們。只需設一下layout,而後,在成員組件那兒用region標明是哪一個區域就是了。Ext.layout.BorderLayout把一塊地盤分紅五個區:eastwestsouthnorthcenter

  我我的很是喜歡這個佈局,由於以它做爲外層佈局的話,就能很方便的實現cnblogs同樣的效果,我到如今還不知道那個左邊列固定寬,右邊列佔滿剩餘屏幕的佈局是怎麼搞的,除非寫javascript代碼在window.onload中手工調,不然,全靠css,真的是想不出辦法來,後來,我也找到一個辦法:用table。table有一個特性,能夠把它設成佔滿整個水平方向,第一列固定寬,第二列自動就是剩餘的。不過,不曉得有沒有純css的解決方式,老實說,div+css實在太難控制了,table在水平方向上的佈局優點仍是很大的。好比,同一行,放兩個內容,左邊的左對齊,右邊的右對齊,用div就麻煩了,又是浮動,挖空心思,用table就很顯然,兩個格:一個align=left,一個align=right。這話題扯遠了。發牢騷罷了。

  8、怎樣使得Panel能被改變大小

  事實上,若是真的panel能被改變大小,那麼能夠考慮使用window。只要把dragable設成false就成了。若是不喜歡那些按鈕,應當也能夠想到辦法去掉的。panel自己沒有這個功能。不過,ExtJs有一個類提供這種功能,即:Ext.Resizable。它的用法很簡單,以下:

var resizer = new Ext.Resizable("element-id", {
    handles: 'all',
    minWidth: 200,
    minHeight: 100,
    maxWidth: 500,
    maxHeight: 400,
    pinned: true
});

  由上可知,它的功能是爲一個指定的元素提供可改變大小的功能。這個功能不出奇吧。怎麼把它用於panel。嘿,其實就一個關鍵,怎樣取得x-panel所在元素的id。這個好辦,事實上,這件事我曾在Ext.Panel篇一中就論述了。二種方法:panel.el或者panel.getEl()都同樣。

  所以,代碼應當這麼寫:

  var resizer=new Ext.Resizable(panel1.getEl(),{handlers:'all',pinned:true});

  resizer.on('resize'function(){panel1.updateBox(panel1.getSize());});

  在建立好panel以後,緊跟着加上這兩行代碼就好了。爲何要加上後面的那行呢?由於這個Ext.Resizable只會改變panel.getEl()的大小,可是裏面的內容並不會所以而發生變化,結果是新增長的那一部分是灰色的。那是proxy的顏色吧。要把panel的子組件調整到實質大小必需要updateBox,可者是setWidth、setHeight。

  這個功能蠻簡單,若是要對Ext.Resizable的詳情進行了解,請參見其官方文檔。

  9、怎樣爲Panel提供工具欄

  這個問題重要,panel提供兩種工具欄:tbar、bbar。可是定義的方法都同樣。首先,我要研究一下tbar的類型:Object/Array,api文檔說:能夠是toolbar對象、能夠是toolbar的config、還能夠是按鈕的數組,固然也能夠是前二者的數組。目標清楚了,就要小小地研究一下toolbar,toolbar這個主題比較大,事實上應看成爲一個專題來搞的。不過,先搞清楚個大概用着先吧。

  這兒有一篇關於Ext.Toolbar的好文章,點此處查看!關於在Ext.Panel中使用工具欄,最直觀、傻瓜式的用法,點此處查看。關於toolbar的更詳細的研究、使用方法將在下一篇中給出。

 

  至此,關於Ext.Panel的常見問題都在這兒了,搞清楚了這些,基本上常規需求均可以實現了。

24.         extJs 2.0學習筆記(組件總論篇)

  組件正是extJs的亮點所在,像日常要用的Ext.Window、Ext.tabpanel都是咱們最喜歡的好東西。要完全弄清楚這中間的機制啊。

  我查到了一些參考資料:

  原本打算仔細分析一下Observable、Component、BoxComponent、Container這幾個基類的源代碼,可是不巧,正好看到了上面列出的教程中的「ExtJs實用開發教程」,這個系列教程寫得太好了,以致於只要看一看教程就能夠寫出知足常見需求的代碼來。並且,有了它,對於全部組件使用都有了一個大概映像。不至於不曉得如何下手,而非得去啃代碼了。萬歲啊。

  如今大概映像有了。繼續看代碼。

  Observable類是整個組件架構的最頂層的類。它的用途就是爲組件提供統一的事件管理接口,有人問?怎麼又是事件管理啊。Ext.Element不是已經封裝了事件管理的機制了嗎?也有人問:不是有了Ext.Element了嗎,爲何還要Ext.Component呢?其實這兩個問題是一件事。

  Component是組件,組件不是一個元素,而是若干個元素的有機集合。Element的確是有事件,可是,組件的事件不一樣於元素的事件,它是一個更高級別的概念。

  Observable類沒什麼了不得的。事件管理嗎?其本質就至關於c#/java中的容器類,原理就是內置一個數組或者是{},而後提供一個接口來add、remove、removeAll、find。這些東西在c#/java中早就炒得倒背如流了。而所謂的addEvents方法本質就是爲一個map加了一羣的key。找到代碼,果不其然,就是依賴於this.events,它初始值爲{}。它怎樣實現事件的註冊、反註冊、事件包裝呢?說出來也蠻容易。內部依託於一些容器(像數組、json對象),而後把全部的要監聽的元素、監聽元素的事件、事件處理函數、scope、options都保存在裏面,時機一至就fireEvent了。怎麼包裝事件呢?那段代碼我也沒有去看了,方法沒法兩種:

  1、對於本來就有事件,類爲對應元素建立一個默認處理函數,在這個處理函數裏面會FireEvent對應元素此事件的事件處理函數。

  2、本來沒有事件,像Ext.Component的beforeDestory之類的事件,這種事件就要本身在相應的地方手工FireEvent了。

  Ext.Component類,這是個很重要的類。對此我只有兩點要介紹:

  1、關注它的config。組件構造函數的形參Ext.Element/String/Object最爲重要的是,形參能夠是一個json對象,對於這個對象的各個成員的意義,這個是之後寫代碼的關鍵,例如:

  var wnd=new Ext.Window({titile:"這是伯平的標題欄",html:"這是窗口的內容!",width:400,height:300,layout:"fit"});

  上面代碼是建立一個簡單的div窗口,這是最普通的構造了,通常,還有一個items的成員,在它裏面定義窗口的內容。items是一個數組,不過我與大夥同樣都會產生一個疑問:只憑一個數組就能定義窗口嗎?那些窗口成員的位置、大小怎麼搞呢?關於樣式,固然能夠爲每一個數組成員填加一個成員cls,用它設class。可是,佈局呢?難道所有是absolute不成?有門的。你看上面定義窗口的時候不是有一個layout嗎?fit是一種佈局方式,它的做用是,容器中只能一個可見成員,且這個成員會填充滿整個容器。關於佈局類這些東西,做者是參考自java的swing了。如今,就連dotnet的winforms也有相似的內容了。

  2、組件的統一管理,在Ext.Component的構造函數中有以下代碼:

  Ext.ComponentMgr.register(this);

  extJs提供一個全局的類Ext.ComponentMrg。顧名思意:component manager。我跑過去看這個類的源代碼,它內部用一個叫:Ext.util.MixedCollection的類來作容器,整個代碼不多,加上註釋才100來行。register就是往Ext.util.MixedCollection裏面add而己。固然,有add就有remove。這兒也有兩個東西要注意:

  1. 關於Ext.getCmp(id)
    getCmp : function(id){ return Ext.ComponentMgr.get(id); }這是Ext類中的代碼,這個get如今能理解它的用途了吧,也就是說,只要一個組件被建立出來,它就會被加到這個容器中來,而後隨時能夠用它的id取出來繼續用。因此,你甚至不用保存建立的組件的實例。能夠直接用getCmp取出來。
  2. 關於Ext.reg

它用於註冊一種組件類型,這個東西我在之前也沒有發現它的做用,如今看了Ext.Component才明白。且看它的代碼:
registerType : function(xtype, cls){
            types[xtype] = cls;
            cls.xtype = xtype;
}
xtype就是新註冊的組件類型,它是字符串,而cls不是class哦,它是這個類對應的function,文檔上說是這個類對應的構造函數(就是constructor啦)。真相大白了。

  關於Component,我要說的就這麼多:一個config,一個組件管理器。

 

  Ext.BoxComponent

  Ext.BoxComponent繼承自Ext.Component,它的主要做用是封裝元素的設置位置、寬度的功能。有人說,位置、寬度的設置在Ext.Element不是早就封裝了一大把嗎?這是個編程技巧,在組件這種高層面上,元素是低層面的,應當儘可能把這些內部實現的東西隱藏。否則,無論三七二十一什麼事都去訪問Ext.Component.getEl()方法,而後隨心所欲,那就打破了封裝性了。這至關於設計模式中的「外觀模式」。功能早就有,只是提供一個高層的接口來訪問罷了。

 

  Ext.Container

  Ext.Container繼承自Ext.BoxComponent。對於它,我先介紹一篇分析得不錯的文章!點此處進入

  一句話,這個類是封裝佈局細節的類,用專業的術語來說,它是extJs中一堆佈局類的外觀類,經過它,咱們基本上不要去管那些佈局細節的事情了,只要在建立組件實例時的config中,加入一個layout:XXXX就成了。若是要對layout初媽化配置,傳說中,Ext.Container的config json提供一個叫:layoutConfig的成員。它的詳細文檔就得看API了。固然,這兒我仍是要點一下一些最經常使用的API。

  config object:width/height/activeItem/defaultType/default/items/layout/layoutConfig/listeners/moniterResize

  經常使用屬性:items/ownerCt

  經常使用方法:add/insert/remove/findXXXX

  你看,這個使用簡單啊。那麼是否是全部其餘組件都是繼承自Ext.Container呢。固然不是,只有像Ext.Panel、Ext.TabPanel、Ext.Window這種複合型的組件纔是從Ext.Container繼承的。

  到此爲止,必定有人對於使用經常使用組件有些迫不急待了,點此處讓大夥來瞧瞧

 

  好了,大概就是這樣了,下面提供一個ExtJs 2.0的組件結構圖:

  

25.         extJs 2.0學習筆記(Ext.Element API總結)

  Ext.Element API比較多,大夥用的時候也難以在短期把住它的脈絡,主要功能。這個給個總結,而不是一個API說明。說到API說明,網上早有大俠作得蠻不錯的了。

位置設置:

getX()   取得相對於頁面的x座標
getY()   取得相對於頁面的y座標
getXY() 取得相對於頁面的x,y座標,用法:ele.getXY()[0]/[1]
getOffsetsTo(el)  取得相對元素el的座標,返回值[x,y]
setX(x,animate)   設相對於頁面的x座標,animate爲true則開啓默認動畫效果
setY(y,animate)  同上
setLeft(left)   設style.left
setTop(top)    設style.top
setRight(right)  設style.right
setBottom(bottom) 設style.bottom
setXY(pos,animate) 設相對於頁面的x,y,至關於setX,setY。用法:setXY([x,y],true)
setLocation(x,y,animate) 至關於setXY。
getRegion()        return {top=t,left=l,width=w,height=r}
getHeight(true|false)    true不包括邊框、內邊距,false包括
getBorderWidth(anthor)
getPadding(anthor)
getComputedHeight()  包括邊框、內邊距
getComputedWidth()
getSize()   至關於getWidth、getHeight   {width:w,height:h}
getStyleSize()   取style.width、style.height,且不包括邊框{width:w,height:h}
getViewSize()    取視口大小{width:w,height:h}
getValue()     若是有value屬必就取它
setWidth(width,animate)     設style.width
setHeight(height,animate)    設style.height
setSize(width,height,animate)
setBounds(x,y,width,height,animate)   至關於setSize、setXY
setRegion(region,animate)      至關於setBounds
getScroll()            取得當前視口在文檔中水平、垂直方向上的偏移,返回{left:l,top:t}

setOpacity(opacity,animate)
getLeft(local)    false至關於getX,true至關於style.left
getRight(local)   false至關於getX+getWidth,true至關於getLeft(true)+getWidth()
getTop(local)   false至關於getY,true至關於style.top
getBottom(local)
position(pos,zIndex,x,y)  string:pos,取static,relative,absolute,fixed
                          zIndex設z序,x,y用來調用setXY的
clearPositionsing(value)  做用非得看代碼
    clearPositioning : function(value){
        value = value ||'';
        this.setStyle({
            "left": value,
            "right": value,
            "top": value,
            "bottom": value,
            "z-index": "",
            "position" : "static"
        });
        return this;
    }

getPositioning()  取值格式如上{……}
setPositioning(pc)  用法同applyStyles
setLeftTop(left,top)  就是設style.left,style.top


moveTo(x,y,animate)    至關於setXY
move(direction,distance,animate)   頗有用,direction移動方向,取t,l,r,b。
                    distance是移動的距離,animate是否啓用動畫效果

getAnchorXY(anchor,local,s)   取得對齊到某處的頁面x,y座標
getCenterXY()          取得對齊到視口中央的頁面x,y座標
getAlignToXY(el,p,o)       取得對齊到某元素某處的頁面x,y座標

alignTo(element,position,offsets,animate)  對齊到元素的某處,容許偏移、動畫
anchorTo(el,alignment,offsets,animate,monitorScroll,callback)  對齊到元素


center(centerIn)   對齊到視口中央
getBox(contentBox,local)  contentBox=false包括邊框、內邊距 local=false獲取頁面座標
setBox(box,adjust,animate)   box包括邊框、內邊距
getFrameWidth(sides,onlycontentBox)

repaint()    強制刷新元素

 


關於樣式、屬性設置

addClass(String/Array className )
removeClass(String/Array className)
replaceClass(String oldClassName, String newClassName )
radioClass(String/Array className )
toggleClass(String className )
setStyle(name,value)
getStyle(name)
hasClass(className)

addClassOnClick(classname)
addClassOnFocus(classname)
addClassOnOver(classname)
hover(classsname,bool preventFlicker)

頁點操做:
append(ele)
appendTo(ele)
replace(ele)
replaceWith(ele)
insertBefore(ele)
insertAfter(ele)
insertFirst(ele)
insertHtml(where,html,returnEl)
insertSibling(el,where,returnDom)
remove()
createChild(config,HTMLElement insertbefore,returndom)


first(selector,returndom)
last(selector,returndom)
next(selector,returndom)
prev(selector,returndom)
parent(selector,returndom)
child(selector,returndom)
up(selector,maxdepth)
down(selector,maxdepth)

query(selector)

contains(HTMLElement/string el)

show(animate)
hide(animate)
toggle(animate)
setVisible(boolean visible,animate)


update(html, loadScripts, callback)

特殊的
hover( Function overFn, Function outFn, [Object scope] ) : Ext.Element
mask(msg, msgCls)
unmask()
load( String/Function url, [String/Object params], [Function callback], [Boolean discardUrl] )
focus()
blur()


事件註冊:
on(eventname,fun)
un(eventname,fun)
addListenser/removeListenser/removeAllListeners

 

  在上面,我把Ext.Element的全部API進行分類,日常要完成什麼功能,一查即知,並且,我這兒給出那些只有細微差異的API的不一樣之處。讓人一看即知,固然,若是對最基礎的API都有疑問,這兒有一篇好文章,能夠補此不足,點此處訪問它

26.         extJs 2.0學習筆記(Element.js篇)

  Element.js這個文件包含了整個extjs框架中最爲核心的部分,它對DOM元素進行超強的封裝。源文件就有3054行,儘管這中間有好可能是註釋,可是,在個把月前,我不敢想像我會要拿着幾千行的js文件來研究。呵呵。

  就我目前而得知的情報,Ext.Element類至少包含以下功能:

  1、爲許多DOM動做建立Animation(動畫),例如setWidth,它提供一個可選項來得到動畫效果

  2、提供一個偉大的load方法,能夠直接ele.load({url:xxxxx}的方式來異步加載數據。超爽、超酷啊。

  其餘功能我目前不知,這是看了別人的教程有了這樣一個大概的映像。若是要對它得到一個大概映像,點此處訪問相關資源!經過這個資源,幾乎就能夠動手寫程序了。

  廢話就很少講了,仍是來研究研究源代碼。

  1、Ext.Element的緩存機制

Ext.Element = function(element, forceNew){
    var dom = typeof element == "string" ?
            document.getElementById(element) : element;
    if(!dom){ // invalid id/element
        return null;
    }
    var id = dom.id;
    if(forceNew !== true && id && Ext.Element.cache[id]){ // element object already exists
        return Ext.Element.cache[id];
    }

    this.dom = dom;

    this.id = id || Ext.id(dom);
};

  Ext.Element提供了緩存機制,做用:提升性能;原理:讓構造過Ext.Element存放在json對象中,若是要再次得到這個對象就不用再次構造,只需從緩存中取出便可。原理很簡單。

  上面函數是Ext.Element的構造函數,其中forceNew表示是否強制建立一個新對象,無論緩存中是否已存在。這個構造函數還強制爲元素生成id。

  緩存定義在哪?在代碼的最後面有一行代碼:El.cache = {};可見,緩存是全局的。這是必然。再看看大夥日常用得最多的函數。Ext.Element.get。這個函數都有四十幾行的代碼,由於整個函數考慮到可能傳入參數的類型有好幾種的狀況,狀況多起來,因此有點多。

  2、Ext.fly倒底有什麼用?

  Ext.Element有一靜態成員fly。它也是得到一個Ext.Flyweight對象的實例。固然,它也是對元素的包裝,請見代碼:

  var flyFn = function(){};
  flyFn.prototype = El.prototype;
  var _cls = new flyFn();

  // dom is optional
  El.Flyweight = function(dom){
   this.dom = dom;
  };

  El.Flyweight.prototype = _cls;
  El.Flyweight.prototype.isFlyweight = true;

  看清代碼了吧?能夠說,Flyweight是繼承自Element的。不過,正如其名,它是輕量級的。爲何這麼說呢?見fly的代碼:

El.fly = function(el, named){
    named = named || '_global';
    el = Ext.getDom(el);
    if(!el){
        return null;
    }
    if(!El._flyweights[named]){
        El._flyweights[named] = new El.Flyweight();
    }
    El._flyweights[named].dom = el;
    return El._flyweights[named];
};

  這個代碼的關鍵是,它老是會取得同一個Flyweight對象,用fly取的時候,只要沒有傳named,全部取的對象都同一個,換的只是dom罷了。

  有人問這有什麼好處?好處大了,若是有1000個元素,要調用它們的hide隱藏,若是用Ext.get的話,就會建立1000個Element對象,若是用fly,那隻會建立一個對象。這對性能帶來巨的提高。因此,在有一些批量式的操做時,用fly要好一些。

  3、對Element.findParentElement.findParentNode的質疑!!

  原來如此,原本覺得它是尋找的對象不包括本身,我總覺得沒有獲得結果,原來,這兩個函數是從本身找起的,若是一個元素是div,若是它用findParent找div祖先的話,那找的老是本身。

  這個問題是解決了,不過,我對findParent的代碼有疑問,它裏面用Ext.getDom(maxDepth)來得到最極限層次的那個節點,事實上,我把getDom傳數字的話只會返回數字自己,根本不會返回元素。這個問題我一直想不通。不過,這並不會影響表面上的功能。只是設maxDepth至關於白設了。

  4、Element的動畫支持

  Element要使用動畫有三大類方法。

  1. 直接調用Ext.Elementanimate函數,它創建於Ext.lib.Anim類的基礎之上,而Ext.lib.AnimAdapter裏面的類。
  2. 在調用Ext.Element的一些設置大小、位置、範圍、透時度時,那些函數每每有一個參數,anim,設一設它,也能得到動畫效果。
  3. 調用從Ext.Fx類中繼承過來的方法,若是頁面包含了Ext.Fx,那麼就能夠用全部在Ext.Fx中定義過的函數了。

  通常多用後面兩種方法。出人意料的是,Ext.Element繼承了Ext.Fx。代碼上反應在哪裏呢,在Ext.Fx的最後面,有這樣一行代碼:Ext.apply(Ext.Element.prototype, Ext.Fx);這樣一來,在Element中就可放心地使用特效了。關於對Element使用動畫,這個如今不是研究重點,這個Ext.Fx要研究的內容。在此一筆帶過,實在急於這個問題的,能夠點此處閱讀相關參考資料

  5、設置位置、大小、絕對位置、相對位置等等於關定位、範圍的函數

  這是個大問題,事實上,前一週我重點就在搞這個問題,例如:

  1. 如何取得相對於定位容器的座標
  2. 如可取得相對於頁面文檔的座標
  3. 如何取得元素的大小,包括邊框、內邊距、實際內容
  4. 如何取得相對於元素的座標(偏移量)
  5. 如何取得視口大小
  6. 如何取得當前文檔水平滾動、垂直滾動的距離
  7. 如何取得當前元素相對於視口左上角的座標

  問題多吧。這些問題在日常計算時多要用到這些量,然而這些量與瀏覽器類型嚴重相關。不一樣瀏覽器取法不同。麻煩、頭痛啦。還好,這個問題Ext.Element都對此進行了封裝。不用咱們煩心了。固然,上面還僅僅是取得,還有設置這些量的問題,這就至少十5、六個函數了。Ext.Element又是英文文檔,給咱們的理解形成了困難吶。下面來把這些東西找出來。到了這裏,我再次想起asp.net ajax,這個東西如今與extJs比起來屁都不是啊。在asp.net ajax中,就封裝一丁點的東西,它裏面的DomElement至關於Element了,只是功能徹底不能比,就只有create、addClass、removeClass、toggleClass,關於我上面提出的七個問題,一個都沒有解決。這個框架有跟沒有同樣。若是有兄弟正在用asp.net ajax,最好仍是換一換,換誰都不要用asp.net ajax啊。

  關於這個問題,我一併交到下一文中,下一篇中主要是把Ext.Element中的API歸類,好比要建立元素節點並插入某個地方,有哪些方法?

27.         extJs 2.0學習筆記(DomHelper.js篇)

  這個文件定義的是Ext.DomHelper類。做用是提供一些Dom的操做。這個類不是靜態類。

  這個類第一個函數createHtml是一個私有函數,用於從指定轉入建立對應的html文本。這個類有多種狀況,根據源代碼分析:

  var createHtml = function(o){}

  o的取值可能有:string(現成的html字符串)、Array(JSON對象數組)、object(JSON對象)

  可見,createHtml的主要做用是把一個JSON序列化爲html字符串。那麼,createHtml能識別的JSON對象有什麼格式要求呢?固然有,描述以下:

  {tag:string,          //元素的標記名,若是沒有,默認爲div

  children|cn:string|Array|json,  //子結點對應的json數組或字節點的html或單個json

  html:string,          //對應的html,若是有cnchildren屬性就忽略

  style:function|string|json,    //元素的樣式,能夠是函數,字符串,json對象

  cls:string,           //元素的class屬性的值

  htmlFor:string         //元素的For屬性,

  x:y              //x表示其餘名字,y表示非函數、非空內容

  }

  我發現,style儘管容許是放一個function,可是,若是真是function的話,那麼對應的style並不會生成,由於以下代碼:

  if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;

  若是值是函數,就continue了。這應當是extJs程序員不當心的bug。

 

  下面有一個私有函數:createDom,定義爲var createDom = function(o, parentNode){……},用於根據一個o建立dom結構樹,並把它放到parentNode這個節點下。o的狀況跟上面的createHtml同樣。這兒我學到的是:documentFragment,這個函數用於建立一個文檔碎片,爲何用它呢?點此處見詳情!document結構下,每appendChild一次就引起一次樹的刷新,這將影響性能,而使用Fragment,至關於先將所節點建立好好一緩存,而後一次性appendChild到document(注意,這兒的document泛指文檔樹)下。

 

  var insertIntoTable = function(tag, where, el, html){……}

  它的做用是往表裏面插入單元格或行、或tbody或在table以前或以後插入指定html內容的文本。即:

  tag:null/td/tr/tbody

  where:beforebegin/afterend/afterbegin

  el:節點的引用

  html:要插入的內容

 

  後面就是insertHtml了,這個函數是關鍵,惋惜裏面好多函數不熟,整個DomHelper中的那些函數,好多都是創建在它的基礎之上的。像什麼:insertBefore、insertEnd、insertFirst、append。overwrite是重寫已有節點的innerHTML用的。至此功能卻是齊全了。

  其實,總結Dom操做,無非就是插、刪、修改。這兒封裝的都是插入,由於修改簡單,改它的innerHTMl就是了,何況這兒還有一個overwrite。刪也簡單,有Ext.destroy。Ext.Element.remove。

  

  今天精神有點很差,我看了一大把的js文件。每一個文件的代碼量都很多。這要看到何時啊。不能這麼幹了。不過,仍是打算花大力氣研究一下Ext.Element。

28.         extJs 2.0學習筆記(ext.js篇)

 要是之前,我鐵定成天處處找教程看,光說不練,如今覺悟了,看教程看得最多,不必定能看完,看完了不必定能比做者更明白,看明白了不必定能用得好。因此看教程其實好處不大,只能做爲小小的參考。不少東西看別人的始終是沒有用。只有將實驗進行到底纔是王道……

  這兒主要是代碼分析。

  研究工具:Dreamweave cs3(裝那個extJs 2.0插件老裝不上)Aptana(一個好處,好看代碼,有括號匹配,json語法好是好,就是括號多了,搞清在哪兒結束)

  發現,extJs的代碼最喜歡用json語法定義,類基本上都是用json語法定義的。而不是在外面一大路的xx.prototype.yyyy=function(){……}。不過這種語法蠻清晰。我喜歡。

  extJs時面只有一個類:Ext,它是一個靜態類。提供了常常要用到的函數。

Ext.apply = function(o, c, defaults){
    if(defaults){
        // no "this" reference for friendly out of scope calls
        Ext.apply(o, defaults);
    }
    if(o && c && typeof c == 'object'){
        for(var p in c){
            o[p] = c[p];
        }
    }
    return o;
};

  這是apply函數,做用其實至關於克隆,它把對象c中的成員所有複製到o中去。若是有defaults,也把它的內容複製到o中。這兒其實揭示javascript的一種語法:

  javascript中的對象的成員有兩種引用方法:

  1、o.propertyName

  2、o[propertyName]

  這段代碼關鍵就在o[p]=c[p]。這個要理解。儘管如此,可是不能像下面同樣作:

  var newelem=new Object();
  Ext.apply(newelem,Ext.getDom("a1"));
  Ext.getDom("form1").appendChild(newelem);

 

  下面一大段的代碼,因爲dw很差看代碼,半天才曉得那兒是個(function(){……Ext.apply(Ext,{……}})(),這是我把概述出來。這樣寫呢,實在有點叫人彆扭,做者的意圖是想把這相關的一段所有放到括號中,以避免形成理解上的混亂。能理解。不過,這種寫法不大招人喜歡。

 

        applyIf : function(o, c){
            if(o && c){
                for(var p in c){
                    if(typeof o[p] == "undefined"){ o[p] = c[p]; }
                }
            }
            return o;
        }

  這是applyIf的代碼,事實上,在文檔上面,它的描述有問題,應當是是當o,c兩個對象都存在時,則把o中不存在,c中存在的屬性複製到o中,且屬性名不變。而不是所謂「若是o不存在時就把屬性複製到o中」,哪有這種說法的。另外,判斷一個對象是否是存在,最嚴謹的仍是用typeof的方法。

 

addBehaviors : function(o){
            if(!Ext.isReady){
                Ext.onReady(function(){
                    Ext.addBehaviors(o);
                });
                return;
            }
            var cache = {}; 
            for(var b in o){
                var parts = b.split(
'@');
                if(parts[1]){ // for Object prototype breakers
                    var s = parts[0];
                    if(!cache[s]){
                        cache[s] = Ext.select(s);
                    }
                    cache[s].on(parts[1], o[b]);
                }
            }
            cache = null;
        }

  這個地方巧妙在於依賴於Ext.isReady。這個屬性我估計應當是在onload第一行將它設成true的,它的做用就是用於標誌當前是否是已經文檔模型加載完了。前面幾行的意思:若是dom模型尚未加載完,沒有準備好,就將這些事件註冊代碼交給onload去作。即Ext.onReady。

  若是DOM模型已加載完,那麼就立刻註冊事件,區別:前者是延遲註冊、後者是立刻註冊。爲何要延遲,由於DOM都沒有建立完,有些元素在DOM樹中還不存在,固然就無法設置它了。其他的地方則不足道,後面的關鍵就是Ext.select了。

 

        id : function(el, prefix){
            prefix = prefix || "ext-gen";
            el = Ext.getDom(el);
            var id = prefix + (++idSeed);
            return el ? (el.id ? el.id : (el.id = id)) : id;
        }

  這兒有一個技巧:prefix = prefix || "ext-gen",這是最簡捷的代碼啊。原本要一個if語句的。

 

  extend、namespace兩個函數硬是沒有看懂,等水平高了再來研究。

 

  urlEncode的源代碼原理簡單,可是,要是個人話仍是無法寫得這麼清楚,主要是狀況比較多。這兒主要是學到了數組的push,原來覺得push只能傳一個參數,沒想到能一次傳多個。發現,不少時候,在構造一個複雜的字符串時都是用到數組的。至於urlEncode的做用,就是把一個JSON對象編碼成一個查詢字符串。

        each : function(array, fn, scope){
            if(!Ext.isArray(array)){
                array = [array];
            }
            for(var i = 0, len = array.length; i < len; i++){
                if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
            }
        }

  這個函數的功能並非像它的名字同樣簡單啊,這兒又學到了:

  1、原來構造單元素數組能夠直接這樣寫:a=[a]。

  2、scope在這兒是默認僞調用者,同時,還把當前數組元素值、序號、數組引用都傳過去了。這個可能在fn中用得着。要注意。

  另外就是x===false這個語句要注意。要知道undefined==false。

        callback : function(cb, scope, args, delay){
            if(typeof cb == "function"){
                if(delay){
                    cb.defer(delay, scope, args || []);
                }else{
                    cb.apply(scope, args || []);
                }
            }
        }

  吃了一驚,Function何時有個成員叫defer了?後來才知,defer是extJs擴展出來的。delay是時延。老實說scope這個東西不能言傳只可意會,不看代碼是不清楚的。事實上javascript中的確是存在defer屬性的。用於修飾script元素的,確實是用於延遲script裏面內容的加載。詳情見此處

        destroy : function(){
            for(var i = 0, a = arguments, len = a.length; i < len; i++) {
       var as = a[i];
      if(as){
        if(typeof as.destroy == 'function'){
          as.destroy();
      }
      else if(as.dom){
          as.removeAllListeners();
          as.remove();
      }
                }
            }
        }

  這個函數用來銷燬對象,由代碼可知一點,extJs鼓勵你們在建立本身的類有必要的話就寫destroy。如大量沒用的dom元素。在這裏,destory至關於析構造函數同樣。至於removeAllListenners,remove這兩個函數,它們是Ext.Element類的成員。

  removeNode : isIE ? function(){
            var d;
            return function(n){
                if(n && n.tagName != 'BODY'){
                    d = d || document.createElement('div');
                    d.appendChild(n);
                    d.innerHTML = '';
                }
            }
        }() : function(n){
            if(n && n.parentNode && n.tagName != 'BODY'){
                n.parentNode.removeChild(n);
            }
        }

  這個代碼做用顯然,就是刪除一個結點。可是這個代碼的寫法實在有點讓人難以接受啊。最鬱悶是若是ie,那麼,那個參數n是怎麼傳進去的呢,由於外面罩住的那個函數沒有參數,原本沒有參數也好辦,關鍵是外面的那個函數根本沒有傳參數給return裏面的函數,這竟然也能傳進去,見識到了。

  通過一番實驗與琢磨,發現,其實並非外面的函數能傳參給裏面的那個函數,實在是由於那個()用得好,若有:

  var do1=function(){return function(n){}}();

  關鍵是要外面的函數{}以後要立刻「自調用」一下,這樣就會返回一個結果,這個結果是個函數表達式,它就能傳參了。因此若是外面的函數沒有()的話,那麼實際調用將必須寫成:do1()(3)的形式,連寫兩個括號。。這個問題我想了很久,終於想清楚了。

    createCallback : function(/*args...*/){
        // make args available, in function below
        var args = arguments;
        var method = this;
        return function() {
            return method.apply(window, args);
        };
    }

  顧名思意,回調。這個函數是對Function對象的原型擴展。因此,全部函數都有這個成員。例如:

  function A(){}

  B=A.createCallback();

  B();

  最後B()執行調用的是A。有人說,既然調用B就至關於調用A,還不如直接用

  function B(){A.apply(window,this.argments);}

  的確,這樣確實能夠達到差很少的目的,可是,寫代碼要注意封裝。儘管這隻有一行代碼,可是,相對於客戶程序員來講,createCallback比apply親切多了,並且,它還節省了很多字符,這就節省帶寬。

  什麼時回調?讓別人來調,那爲何不定義在那個調用者裏面?由於,只有定義在別人的裏面才能夠得到別人的信息。

  固然,在這兒我仍是學到了一點,之前沒意識到,怎樣把外層的this傳給內層的function。只需method=this。

  有一些Ext下的函數並無定義在ext.js中。如:Ext.onReady、Ext.reg、Ext.select、Ext.query。

相關文章
相關標籤/搜索