概述: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 } 386 387 }); |
|