概述:
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