西沙璞玉
          愛不容易
          posts - 0,comments - 4,trackbacks - 0

          嘿,別看關鍵就在這兒,事實上,它的代碼很少的哦。加上注釋才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);

          不過,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;
                  };
              }(),

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

            一、obj.xxxx

            二、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源代碼分析完畢,呵呵,因為這個類代碼量較少,故講得詳細。

          posted on 2012-04-28 12:46 @趙 閱讀(1430) 評論(0)  編輯  收藏

          只有注冊用戶登錄后才能發表評論。


          網站導航:
           
          哥哥最近不是很忙
          主站蜘蛛池模板: 沿河| 南宁市| 扶余县| 正安县| 保山市| 尤溪县| 读书| 铜陵市| 东方市| 香格里拉县| 年辖:市辖区| 贡嘎县| 万盛区| 江油市| 沈丘县| 紫金县| 琼中| 子洲县| 攀枝花市| 天全县| 古丈县| 克山县| 积石山| 精河县| 青州市| 凌源市| 夏河县| 利川市| 沧州市| 夏邑县| 阿坝| 嘉定区| 潮州市| 芦山县| 澎湖县| 辽源市| 衡阳县| 甘孜县| 深圳市| 临夏县| 乌审旗|