概述:

jQuery 作為一個輕量級框架,插件格式的控件使用起來非常方便,但是我們基於jQuery寫一套控件,需要我們擴展一些函數,便於控件的繼承和擴展。

擴展函數:

1.         augment(Function r,Object s1): 將指定的方法或屬性放到構造函數的原型鏈上, 函數支持多於2個變量,後面的變量同s1一樣將其成員複製到構造函數的原型鏈上。

2.         cloneObject(Object obj): 拷貝對象(深拷貝)

jQuery 有一個clone方法,但是隻支持HTMLElement,而我們在很多時候需要的是深拷貝對象。

3.         guid(prefix): 生成唯一的id。

用於控件生成時,需要用id管理控件

4.         extend(Function subclass,Function superclass,Object overrides): 實現類的繼承

5.         merge(Object obj1,Object obj2....): 將多個對象的屬性複製到一個新的對象上,如果第一個參數是true,那麼實現的是深拷貝。

6.         mix():封裝 jQuery.extend 方法,將多個對象的屬性merge到第一個對象中。

7.         mixin(Function c,Array mixins,Array attrs): 將其他類作為擴展,集成到指定的類上面。

8.         substitue(String str,Object o,[RegExp regexp]) : 替換字符串中的字段,用於簡單模板

上面是為了實現控件繼承而增加的一些幫助方法,還有一些輔助類的方法,具體代碼如下:

 

1 $.extend(BUI,
  2   {
  3     /**
  4      * 將指定的方法或屬性放到構造函數的原型鏈上,
  5      * 函數支持多於2個變量,後面的變量同s1一樣將其成員複製到構造函數的原型鏈上。
  6      * @param  {Function} r  構造函數
  7      * @param  {Object} s1 將s1 的成員複製到構造函數的原型鏈上
  8      *            @example
  9      *            BUI.augment(class1,{
 10      *                method1: function(){
 11      *   
 12      *                }
 13      *            });
 14      */
 15     augment : function(r,s1){
 16       if(!$.isFunction(r))
 17       {
 18         return r;
 19       }
 20       for (var i = 1; i < arguments.length; i++) {
 21         BUI.mix(r.prototype,arguments[i].prototype || arguments[i]);
 22       };
 23       return r;
 24     },
 25     /**
 26      * 拷貝對象
 27      * @param  {Object} obj 要拷貝的對象
 28      * @return {Object} 拷貝生成的對象
 29      */
 30     cloneObject : function(obj){
 31             var result = $.isArray(obj) ? [] : {};
 32             
 33       return BUI.mix(true,result,obj);
 34     },
 35     /**
 36     * 拋出錯誤
 37     */
 38     error : function(msg){
 39         throw msg;
 40     },
 41     /**
 42      * 實現類的繼承,通過父類生成子類
 43      * @param  {Function} subclass
 44      * @param  {Function} superclass 父類構造函數
 45      * @param  {Object} overrides  子類的屬性或者方法
 46      * @return {Function} 返回的子類構造函數
 47          * 示例:
 48      *        @example
 49      *        //父類
 50      *        function base(){
 51      * 
 52      *        }
 53      *
 54      *        function sub(){
 55      * 
 56      *        }
 57      *        //子類
 58      *        BUI.extend(sub,base,{
 59      *            method : function(){
 60      *    
 61      *            }
 62      *        });
 63      *
 64      *        //或者
 65      *        var sub = BUI.extend(base,{});
 66      */
 67     extend : function(subclass,superclass,overrides, staticOverrides){
 68       //如果只提供父類構造函數,則自動生成子類構造函數
 69       if(!$.isFunction(superclass))
 70       {
 71         
 72         overrides = superclass;
 73         superclass = subclass;
 74         subclass =  function(){};
 75       }
 76 
 77       var create = Object.create ?
 78                         function (proto, c) {
 79                             return Object.create(proto, {
 80                                 constructor: {
 81                                     value: c
 82                                 }
 83                             });
 84                         } :
 85                         function (proto, c) {
 86                             function F() {
 87                             }
 88 
 89                             F.prototype = proto;
 90 
 91                             var o = new F();
 92                             o.constructor = c;
 93                             return o;
 94                         };
 95       var superObj = create(superclass.prototype,subclass);//new superclass(),//實例化父類作為子類的prototype
 96         //superObj1 = new superclass();//作為superclass屬性
 97       subclass.prototype = BUI.mix(superObj,subclass.prototype);     //指定子類的prototype
 98       //superObj1.constructor = superclass;
 99       subclass.superclass = create(superclass.prototype,superclass);  
100       //subclass.prototype.constructor = subclass;
101       BUI.mix(superObj,overrides);
102       BUI.mix(subclass,staticOverrides);
103       return subclass;
104     },
105     /**
106      * 生成唯一的Id
107      * @method
108      * @param {String} prefix 前綴
109      * @default 'ks-guid'
110      * @return {String} 唯一的編號
111      */
112     guid : (function(){
113         var map = {};
114         return function(prefix){
115             prefix = prefix || BUI.prefix + GUID_DEFAULT;
116             if(!map[prefix]){
117                 map[prefix] = 1;
118             }else{
119                 map[prefix] += 1;
120             }
121             return prefix + map[prefix];
122         };
123     })(),
124     /**
125      * 判斷是否是字符串
126      * @return {Boolean} 是否是字符串
127      */
128     isString : function(value){
129       return typeof value === 'string';
130     },
131     /**
132      * 判斷是否數字,由於$.isNumberic方法會把 '123'認為數字
133      * @return {Boolean} 是否數字
134      */
135     isNumber : function(value){
136       return typeof value === 'number';
137     },
138     /**
139      * 控制枱輸出日誌
140      * @param  {Object} obj 輸出的數據
141      */
142     log : function(obj){
143       if(win.console && win.console.log){
144         win.console.log(obj);
145       }
146     },
147     /**
148     * 將多個對象的屬性複製到一個新的對象
149     */
150     merge : function(){
151       var args = $.makeArray(arguments);
152       args.unshift({});
153       return $.extend.apply(null,args);
154 
155     },
156     /**
157      * 封裝 jQuery.extend 方法,將多個對象的屬性merge到第一個對象中
158      * @return {Object} 
159      */
160     mix : function(){
161       return $.extend.apply(null,arguments);
162     },
163     /**
164     * 創造頂層的命名空間,附加到window對象上,
165     * 包含namespace方法
166     */
167     app : function(name){
168       if(!window[name]){
169         window[name] = {
170           namespace :function(nsName){
171             return BUI.namespace(nsName,window[name]);
172           }
173         };
174       }
175       return window[name];
176     },
177     /**
178      * 將其他類作為mixin集成到指定類上面
179      * @param {Function} c 構造函數
180      * @param {Array} mixins 擴展類
181      * @param {Array} attrs 擴展的靜態屬性,默認為['ATTRS']
182      * @return {Function} 傳入的構造函數
183      */
184     mixin : function(c,mixins,attrs){
185         attrs = attrs || [ATTRS];
186         var extensions = mixins;
187         if (extensions) {
188             c.mixins = extensions;
189 
190             var desc = {
191                 // ATTRS:
192                 // HTML_PARSER:
193             }, constructors = extensions['concat'](c);
194 
195             // [ex1,ex2],擴展類後面的優先,ex2 定義的覆蓋 ex1 定義的
196             // 主類最優先
197             $.each(constructors, function (index,ext) {
198                 if (ext) {
199                     // 合併 ATTRS/HTML_PARSER 到主類
200                     $.each(attrs, function (i,K) {
201                         if (ext[K]) {
202                             desc[K] = desc[K] || {};
203                             // 不覆蓋主類上的定義,因為繼承層次上擴展類比主類層次高
204                             // 但是值是對象的話會深度合併
205                             // 注意:最好值是簡單對象,自定義 new 出來的對象就會有問題(用 function return 出來)!
206                              BUI.mix(true,desc[K], ext[K]);
207                         }
208                     });
209                 }
210             });
211 
212             $.each(desc, function (k, v) {
213                 c[k] = v;
214             });
215 
216             var prototype = {};
217 
218             // 主類最優先
219             $.each(constructors, function (index,ext) {
220                 if (ext) {
221                     var proto = ext.prototype;
222                     // 合併功能代碼到主類,不覆蓋
223                     for (var p in proto) {
224                         // 不覆蓋主類,但是主類的父類還是覆蓋吧
225                         if (proto.hasOwnProperty(p)) {
226                             prototype[p] = proto[p];
227                         }
228                     }
229                 }
230             });
231 
232             $.each(prototype, function (k,v) {
233                 c.prototype[k] = v;
234             });
235         }
236         return c;
237     },
238     /**
239      * 生成命名空間
240      * @param  {String} name 命名空間的名稱
241      * @param  {Object} baseNS 在已有的命名空間上創建命名空間,默認“BUI”
242      * @return {Object} 返回的命名空間對象
243      *        @example
244      *        BUI.namespace("Grid"); // BUI.Grid
245      */
246     namespace : function(name,baseNS){
247       baseNS = baseNS || BUI;
248       if(!name){
249         return baseNS;
250       }
251       var list = name.split('.'),
252         //firstNS = win[list[0]],
253         curNS = baseNS;
254       
255       for (var i = 0; i < list.length; i++) {
256         var nsName = list[i];
257         if(!curNS[nsName]){
258           curNS[nsName] = {};
259         }
260         curNS = curNS[nsName];
261       };    
262       return curNS;
263     },
264     prefix : 'ks-',
265     /**
266      * 替換字符串中的字段.
267      * @param {String} str 模版字符串
268      * @param {Object} o json data
269      * @param {RegExp} [regexp] 匹配字符串的正則表達式
270      */
271     substitute: function (str, o, regexp) {
272         if (!BUI.isString(str)
273             || !$.isPlainObject(o)) {
274             return str;
275         }
276 
277         return str.replace(regexp || /\\?\{([^{}]+)\}/g, function (match, name) {
278             if (match.charAt(0) === '\\') {
279                 return match.slice(1);
280             }
281             return (o[name] === undefined) ? '' : o[name];
282         });
283     },
284     /**
285      * 使第一個字母變成大寫
286      * @param  {String} s 字符串
287      * @return {String} 首字母大寫後的字符串
288      */
289     ucfirst : function(s){
290       s += '';
291             return s.charAt(0).toUpperCase() + s.substring(1);
292     },
293     /**
294      * 頁面上的一點是否在用户的視圖內
295      * @param {Object} offset 座標,left,top
296      * @return {Boolean} 是否在視圖內
297      */
298     isInView : function(offset){
299       var left = offset.left,
300         top = offset.top,
301         viewWidth = BUI.viewportWidth(),
302         wiewHeight = BUI.viewportHeight(),
303         scrollTop = BUI.scrollTop(),
304         scrollLeft = BUI.scrollLeft();
305       //判斷橫座標
306       if(left < scrollLeft ||left > scrollLeft + viewWidth){
307         return false;
308       }
309       //判斷縱座標
310       if(top < scrollTop || top > scrollTop + wiewHeight){
311         return false;
312       }
313       return true;
314     },
315     /**
316      * 頁面上的一點縱向座標是否在用户的視圖內
317      * @param {Object} top  縱座標
318      * @return {Boolean} 是否在視圖內
319      */
320     isInVerticalView : function(top){
321       var wiewHeight = BUI.viewportHeight(),
322         scrollTop = BUI.scrollTop();
323       
324       //判斷縱座標
325       if(top < scrollTop || top > scrollTop + wiewHeight){
326         return false;
327       }
328       return true;
329     },
330     /**
331      * 頁面上的一點橫向座標是否在用户的視圖內
332      * @param {Object} left 橫座標
333      * @return {Boolean} 是否在視圖內
334      */
335     isInHorizontalView : function(left){
336       var viewWidth = BUI.viewportWidth(),     
337         scrollLeft = BUI.scrollLeft();
338       //判斷橫座標
339       if(left < scrollLeft ||left > scrollLeft + viewWidth){
340         return false;
341       }
342       return true;
343     },
344     /**
345      * 獲取窗口可視範圍寬度
346      * @return {Number} 可視區寬度
347      */
348     viewportWidth : function(){
349         return $(window).width();
350     },
351     /**
352      * 獲取窗口可視範圍高度
353      * @return {Number} 可視區高度
354      */
355     viewportHeight:function(){
356          return $(window).height();
357     },
358     /**
359      * 滾動到窗口的left位置
360      */
361     scrollLeft : function(){
362         return $(window).scrollLeft();
363     },
364     /**
365      * 滾動到橫向位置
366      */
367     scrollTop : function(){
368         return $(window).scrollTop();
369     },
370     /**
371      * 窗口寬度
372      * @return {Number} 窗口寬度
373      */
374     docWidth : function(){
375         var body = document.documentElement || document.body;
376         return $(body).width();
377     },
378     /**
379      * 窗口高度
380      * @return {Number} 窗口高度
381      */
382     docHeight : function(){
383         var body = document.documentElement || document.body;
384         return $(body).height();
385     }
386387