一款类似Ext的轻量级实现UI的JS框架

阅读更多
/*!
 * UC JS Library 1.0.0
 */

// 兼容旧浏览器,早期的浏览器实现中,undefined并不是全局变量。就是说,你要判断一个变量是否是没定义,  
// 你需要这样写if (typeof  a == 'undefined'),不可以写成if (a == undefined)。所以,上面的代码就可以理解了。  
// 右面的window["undefined"],因为window对象没有undefined属性,所以其值为undefined,  
// 把undefined赋值给window的undefined属性上,就相当于把undefined设置成了全局变量,  
// 这样以后你再判断一个变量是否是未定义的时候,就不需要使用typeof,直接判断就可以了。  
//window.undefined = window.undefined;

/**
 * @class webuc
 * UC core utilities and functions.
 * @singleton
 */

UC = {
    /**
     * The version of the framework
     * @type String
     */
    version : '1.0'
};

/**
 * 把对象c中的属性复制到对象o中,支持默认属性defaults设置。
 * 这个方法属于对象属性的一个浅拷贝函数。  
 * 
 * @param {Object} obj The receiver of the properties
 * @param {Object} config The source of the properties
 * @param {Object} defaults A different object that will also be applied for default values
 * @return {Object} returns obj
 * @member UC apply
 */
UC.apply = function(o, c, defaults){
	// 如果默认值defaults存在,那么先把defaults上得属性复制给对象o 
    if(defaults){
        UC.apply(o, defaults);
    }
    if(o && c && typeof c == 'object'){
        for(var p in c){
            o[p] = c[p];
        }
    }
    return o;
};


(function(window, undefined){
	
	// idSeed,用来生成自增长的id值。
    var idSeed = 0,
        toString = Object.prototype.toString,
        
        // ua,浏览器的用户代理,主要用来识别浏览器的型号、版本、内核和操作系统等。  
        ua = navigator.userAgent.toLowerCase(),
        check = function(r){
            return r.test(ua);
        },
        
        /**
         * Iterates an array calling the supplied function.
         * @param {Array/NodeList/Mixed} array The array to be iterated. If this
         * argument is not really an array, the supplied function is called once.
         * @param {Function} fn The function to be called with each item. If the
         * supplied function returns false, iteration stops and this method returns
         * the current index. This function is called with
         * the following arguments:
         */
        isIterable = function(v){
            //check for array or arguments
            if(UC.isArray(v) || v.callee){
                return true;
            }
            //check for node list type
            if(/NodeList|HTMLCollection/.test(toString.call(v))){
                return true;
            }
            //NodeList has an item and length property
            //IXMLDOMNodeList has nextNode method, needs to be checked first.
            return ((v.nextNode || v.item) && UC.isNumber(v.length));
        },
        
        DOC = document,
        
        // isStrict,表示当前浏览器是否是标准模式。  
        // 如果正确的设置了网页的doctype,则compatMode为CSS1Compat,否则为BackCompat 
        isStrict = DOC.compatMode == "CSS1Compat",
        
        // isOpera,表示是否是opera浏览器。
        isOpera = check(/opera/),
        
        // isChrome,表示是否是谷歌浏览器。 
        isChrome = check(/chrome/),
        
        // isWebKit,表示当前浏览器是否使用WebKit引擎。  
        // WebKit是浏览器内核,Safari和Chrome使用WebKit引擎。  
        isWebKit = check(/webkit/),  
        
        // isSafari,表示是否是苹果浏览器,下面代码是对其版本识别。 
        isSafari = !isChrome && check(/safari/),
        isSafari3 = isSafari && check(/version\/3/),
        isSafari4 = isSafari && check(/version\/4/),
        isSafari5 = isSafari && check(/version\/5/),
        
        // isIE,表示是否是IE浏览器,下面代码是对其版本识别。 
        isIE = !isOpera && check(/msie/),
        isIE7 = isIE && check(/msie 7/),
        isIE8 = isIE && check(/msie 8/),
        
        // isGecko,表示当前浏览器是否使用Gecko引擎。  
        // Gecko是浏览器内核,Firefox使用Gecko引擎。  
        isGecko = !isWebKit && check(/gecko/),  
        isGecko2 = isGecko && check(/rv:1\.8/),  
        isGecko3 = isGecko && check(/rv:1\.9/), 
        
        // isBorderBox,表示浏览器是否是IE的盒模式。  
        // 众所周知,IE的盒模式和W3C的盒模式不一致。当IE浏览器在怪异模式下,就会导致错误的盒模式。  
        isBorderBox = isIE && !isStrict,  
        
        // isSecure,表示是否是https连接。  
        isSecure = /^https/i.test(window.location.protocol);


    // 扩展webuc对象,有一些属性,这个文件中没有使用,现在先不解释其作用,后面遇到了再讲。  
    UC.apply(UC, {  
  
        // isStrict,表示是否是标准模式。  
        isStrict : isStrict,  
  
        // isSecure,表示是否是https连接。  
        isSecure : isSecure,  
  
        // isReady,表示Dom文档树是否加载完成  
        isReady : false,  
  
        // SSL_SECURE_URL,这个值在构造隐藏的iframe时,用来设置src属性的,只是当是https连接的时候才用。  
        SSL_SECURE_URL : "javascript:false",  
  
        // BLANK_IMAGE_URL,1像素透明图片地址  
        BLANK_IMAGE_URL : "http:/"+"/webujs.com/s.gif",  
  
        // noop,空函数  
        noop : function(){},
  
        // applyIf,把对象c的属性复制到对象o上,只复制o没有的属性  
        applyIf : function(o, c){  
            if(o && c){  
                for(var p in c){  
                    if(typeof o[p] == "undefined"){ o[p] = c[p]; }  
                }  
            }  
            return o;  
        },  
  
        // 类继承函数,基于javascript的prototype,模仿面相对象的继承特性。  
        // 整个webucJS框架的继承机制就是这个函数实现的。  
        extend : function(){  
            // override函数,用来覆盖prototype上的属性的(私有对象,仅下面的return function内部可以使用) 
            var io = function(o){  
                for(var m in o){  
                    this[m] = o[m];  
                }  
            };  
  
            // Object的构造函数(私有对象,仅下面的return function内部可以使用)  
            var oc = Object.prototype.constructor;  
  
            return function(sb, sp, overrides){  
                // sb表示subclass,sp表示superclass,overrides是默认值为对象型  
                // 如果sp是对象,表示没有传sb变量进来,所以重新设置一下参数  
                if(typeof sp == 'object'){  
                    overrides = sp;  
                    sp = sb;  
                    // 如果overrides中提供了构造函数,那么就用提供的,  
                    // 否则用下面这个匿名函数,匿名函数会调用父类的构造函数  
                    sb = overrides.constructor != oc ? overrides.constructor : function(){sp.apply(this, arguments);};  
                }  
  
                // F是一个临时的类,其prototype指向superclass的prototype,  
                // 同时也把subclass的prototype指向了F对象,  
                // 这样可以避免在类继承的时候,调用superclass的构造函数  
                var F = function(){}, sbp, spp = sp.prototype;  
                F.prototype = spp;  
                sbp = sb.prototype = new F();  
                sbp.constructor=sb;  
                sb.superclass=spp;  
                if(spp.constructor == oc){  
                    spp.constructor=sp;  
                }  
  
                // sb的override的覆盖函数,
                // 作用是把所有属性覆盖到prototype上 
                sb.override = function(o){  
                    UC.override(sb, o);  
                };  
                
                // sbp的override
                // 作用是把所有属性覆盖到 sb上
                sbp.override = io;  
  
                // 设置默认值  
                UC.override(sb, overrides);  
  
                // 继承函数,这样写方便,可以直接从别的类继承新类  
                // 即可以这样写 sb.extend(sp);
                sb.extend = function(o){UC.extend(sb, o);};  
                
                return sb;  
            };  
        }(),  
        
        // 覆盖函数,直接把属性复制到origclass的prototype上  
        override : function(origclass, overrides){  
            if(overrides){  
                var p = origclass.prototype;  
                for(var method in overrides){  
                    p[method] = overrides[method];  
                }  
  
                // 下面是处理IE浏览器在枚举对象的属性时,  
                // 原生的方法toString枚举不出来,即使是自定义的toString也不行  
                if(UC.isIE && overrides.toString != origclass.toString){  
                    p.toString = overrides.toString;  
                }  
            }  
        },  
        
        /**
         * 迭代数组,使用数组中的每个元素作为参数来调用传递进来的function
         * 
         * @param {Mixed}Array/NodeList/Mixed 
         * 如果传递进来的数组不是一个真实的数组,你的function只会被用这个伪数组作参数调用一次
         * 
         * @param {function} fn
         * @param {Object} scope  
         * 指定方法执行的 作用域 ( this 的引用)。 默认为 item 在传递进来的 array 中 的当前 index 。
         */
        each: function(array, fn, scope){
        	
        	// 若为空的时候直接退出循环,由于设置true 所以空字符串可以
            if(UC.isEmpty(array, true)){
                return;
            }
            
            // 如果是不可迭代的或者是三种原始类型 string, number 或 boolean
            if(!isIterable(array) || UC.isPrimitive(array)){
                array = [array];
            }
            
            for(var i = 0, len = array.length; i < len; i++){
            	
            	//回调的this对象若没设scope 则使用array[i], fn 回传的参数
            	// 若在fn中return false 那么each 返回i 并且fn只会调用一次
                if(fn.call(scope || array[i], array[i], i, array) === false){
                    return i;
                };
            }
        },
        
        /**
         * 创建一个命名空间来划分变量和类的作用域,这样他们就不是全局的作用域了
         * 
         * @param {String} namespace1
         * @param {String} namespace2
         * @param {String} etc
         * @method namespace
         */
        namespace : function(){
            var o, d;
            UC.each(arguments, function(v) {
                d = v.split(".");
                o = window[d[0]] = window[d[0]] || {};
                UC.each(d.slice(1), function(v2){
                    o = o[v2] = o[v2] || {};
                });
            });
            return o;
        },
        
        /**
    	 * 转化任何可迭代的对象(含有索引值和一个表长度的属性)为一个真正的数组,不要在字符串上用
         * @param {Iterable} the iterable object to be turned into a true Array.
         * @return (Array) array
         */
        toArray : function(){
            return isIE ?
                function(a, i, j, res){
                    res = [];
                    UC.each(a, function(v) {
                        res.push(v);
                    });
                    return res.slice(i || 0, j || res.length);
                } :
                function(a, i, j){
                    return Array.prototype.slice.call(a, i || 0, j || a.length);
                }
        }(),
        
        /**
         * 迭代数组中的元素,或对象中的每个属性, 
         * 
         * 只是在each上多进行对象遍历
         * 注意:如果你仅仅迭代数组,最好调用 each。
         */
        iterate : function(obj, fn, scope){
            if(isIterable(obj)){
                UC.each(obj, fn, scope);
                return;
            }else if(UC.isObject(obj)){
                for(var prop in obj){
                    if(obj.hasOwnProperty(prop)){
                        if(fn.call(scope || obj, prop, obj[prop]) === false){
                            return;
                        };
                    }
                }
            }
        },
        
        /**
         * 返回true,如果传递进来的值为null、undefined或者一个空的字符串、空数组 (除非 allowBlank参数为 true)。 
         * 
         * @param {Mixed} value The value to test
         * @param {Boolean} allowBlank (optional) true to allow empty strings (defaults to false)
         * @return {Boolean}
         */
        isEmpty : function(v, allowBlank){
            return v === null || v === undefined || ((UC.isArray(v) && !v.length)) || (!allowBlank ? v === '' : false);
        },

        /**
         * 如果传递的值是JavaScript 的数组则返回true,否则返回 false
         * @param {Object} object The object to test
         * @return {Boolean}
         */
        isArray : function(v){
            return toString.apply(v) === '[object Array]';
        },

        /**
         * 如果传递的值是JavaScript 的数组则返回true,否则返回 false
         * @param {Object} object The object to test
         * @return {Boolean}
         */
        isObject : function(v){
            return v && typeof v == "object";
        },

        /**
         * 如果传递的值是JavaScript 的数组则返回true,否则返回 false
         * @param {Mixed} value The value to test
         * @return {Boolean}
         */
        isPrimitive : function(v){
            return UC.isString(v) || UC.isNumber(v) || UC.isBoolean(v);
        },

        /**
         * 如果是一个JavaScript函数则返回true,否则为false。
         * @param {Object} object The object to test
         * @return {Boolean}
         */
        isFunction : function(v){
            return toString.apply(v) === '[object Function]';
        },

        /**
         * 当传递的值为数字时返回true 。如果为无穷数则返回false
         * @param {Object} v The object to test
         * @return {Boolean}
         */
        isNumber: function(v){
            return typeof v === 'number' && isFinite(v);
        },

        /**
         * 如果传递的值为字符串则返回true。 
         * @param {Object} v The object to test
         * @return {Boolean}
         */
        isString: function(v){
            return typeof v === 'string';
        },

        /**
         * 如果传递的值为布尔值则返回true。 
         * @param {Object} v The object to test
         * @return {Boolean}
         */
        isBoolean: function(v){
            return typeof v === 'boolean';
        },

        /**
         * 如果传递的值未定义则为true  
         * @param {Object} v The object to test
         * @return {Boolean}
         */
        isDefined: function(v){
            return typeof v !== 'undefined';
        },
        
        /**
         * True if the detected browser is Opera.
         * @type Boolean
         */
        isOpera : isOpera,
        /**
         * True if the detected browser uses WebKit.
         * @type Boolean
         */
        isWebKit: isWebKit,
        /**
         * True if the detected browser is Chrome.
         * @type Boolean
         */
        isChrome : isChrome,
        /**
         * True if the detected browser is Safari.
         * @type Boolean
         */
        isSafari : isSafari,
        /**
         * True if the detected browser is Safari 3.x.
         * @type Boolean
         */
        isSafari3 : isSafari3,
        /**
         * True if the detected browser is Safari 4.x.
         * @type Boolean
         */
        isSafari4 : isSafari4,
        /**
        /**
         * True if the detected browser is Internet Explorer.
         * @type Boolean
         */
        isIE : isIE,
        /**
         * True if the detected browser is Internet Explorer 7.x.
         * @type Boolean
         */
        isIE7 : isIE7,
        /**
         * True if the detected browser is Internet Explorer 8.x.
         * @type Boolean
         */
        isIE8 : isIE8,
        /**
         * True if the detected browser uses the Gecko layout engine (e.g. Mozilla, Firefox).
         * @type Boolean
         */
        isGecko : isGecko,
        /**
         * True if the detected browser uses a pre-Gecko 1.9 layout engine (e.g. Firefox 2.x).
         * @type Boolean
         */
        isGecko2 : isGecko2,
        /**
         * True if the detected browser uses a Gecko 1.9+ layout engine (e.g. Firefox 3.x).
         * @type Boolean
         */
        isGecko3 : isGecko3,
        /**
         * True if the detected browser is Internet Explorer running in non-strict mode.
         * @type Boolean
         */
        isBorderBox : isBorderBox
    });
    
    /**
     * 创建一个命名空间使得作用域里的变量和类都不会是全局的。
     * 具体指定命名空间的最后一个节点来准确的创建其他不同节点 用例
     * 
     * UC.namespace('Company.data'); // 和上面的语法等效而且更好
	 * Company.Widget = function() { ... }
	 * Company.data.CustomStore = function(config) { ... }
	 * 
     * @param {String} namespace1
     * @param {String} namespace2
     * @param {String} etc
     * @method namespace
     */
    UC.ns = UC.namespace;
})(window);

UC.ns("UC", "UC.util", "UC.util.Constants", "UC.Component");


/**
 * @class String
 * These functions are available on every String object.
 */
UC.applyIf(String, {
	
	/*允许你自定义含有占位符的字符串,并且传递任意数量的参数去替代这些占位符。
	 *每一个占位符必须是唯一的,并且以{0}、{1}…这种格式递增。 
	 *
     *用法示例: 
	 * var cls = 'my-class', text = 'Some text'; 
	 * var s = String.format('
{1}
', cls, text); * @参数1 {String} string 含有占位符,需要格式化的字符串 * @参数2 {String} value1 替代占位符 {0}的字符串 * @参数3 {String} value2 替代占位符{1}的字符串,以此类推 * @返回值 {String} 格式化好的字符串 * @静态方法 */ format : function(format){ var args = UC.toArray(arguments, 1); return format.replace(/\{(\d+)\}/g, function(m, i){ return args[i]; }); }, /** * 用指定的字符填充一个字符串的左侧。对于格式化数字或者日期字符串,这 *一个非常有用的方法。用法示例: *var s = String.leftPad('123', 5, '0'); * result: s = '00123' * * @参数1 {String} string 原来的字符串 * @参数2 {Number} size 返回字符串的总长度 * @参数3 {String} char (optional) 填充的字符串 (默认用" "填充) * @返回值 {String} 填充好的字符串 * @静态方法 */ leftPad : function (val, size, ch) { var result = new String(val); if(!ch) { ch = " "; } while (result.length < size) { result = ch + result; } return result.toString(); }, eqs : function (str1, str2) { return str1.toLowerCase() === str2.toLowerCase(); } }); /** * @class Array */ UC.applyIf(Array.prototype, { /** * Checks whether or not the specified object exists in the array. * @param {Object} o The object to check for * @return {Number} The index of o in the array (or -1 if it is not found) */ indexOf : function(o){ for (var i = 0, len = this.length; i < len; i++){ if(this[i] == o){ return i; } } return -1; }, /** * Removes the specified object from the array. If the object is not found nothing happens. * @param {Object} o The object to remove * @return {Array} this array */ remove : function(o){ var index = this.indexOf(o); if(index != -1){ this.splice(index, 1); } return this; } }); UC.apply(UC.util.Constants, { STATE_ACTIVE : "active", STATE_DISABLED : "disabled", STATE_NORMAL : "normal", POSITION_UP : "up", POSITION_DOWN : "down", POSITION_LEFT : "left", POSITION_RIGHT : "right", keyCode: { ALT: 18, BACKSPACE: 8, CAPS_LOCK: 20, COMMA: 188, COMMAND: 91, COMMAND_LEFT: 91, // COMMAND COMMAND_RIGHT: 93, CONTROL: 17, DELETE: 46, DOWN: 40, END: 35, ENTER: 13, ESCAPE: 27, HOME: 36, INSERT: 45, LEFT: 37, MENU: 93, // COMMAND_RIGHT NUMPAD_ADD: 107, NUMPAD_DECIMAL: 110, NUMPAD_DIVIDE: 111, NUMPAD_ENTER: 108, NUMPAD_MULTIPLY: 106, NUMPAD_SUBTRACT: 109, PAGE_DOWN: 34, PAGE_UP: 33, PERIOD: 190, RIGHT: 39, SHIFT: 16, SPACE: 32, TAB: 9, UP: 38, WINDOWS: 91 // COMMAND } }); UC.Component = function(config){ config = config || {}; if(config.initialConfig){ if(config.isAction){ // actions this.baseAction = config; } config = config.initialConfig; // component cloning / action set up }else if(config.tagName || config.dom || UC.isString(config)){ // element object config = {applyTo: config, id: config.id || config}; } /** * This Component's initial configuration specification. Read-only. * @type Object * @property initialConfig */ this.initialConfig = config; UC.apply(this, config); // UC.Component.superclass.constructor.call(this); this.initComponent(); }; UC.Component.prototype = { /** 父类id **/ appendTo : "", /** 添加的父节点 */ id : "", disabled : false, /** * @cfg {Boolean} hidden * Render this component hidden (default is false). If true, the * {@link #hide} method will be called internally. */ hidden : false, /** * True if this component has been rendered. Read-only. * @type Boolean * @property */ rendered : false, // private xtype : 'UC.Component', listeners : {}, tips : "", self : null, getSelf : function(){ return this.self; }, initComponent : UC.noop, /** *在传递进来的HTML元素中渲染当前组件。 */ render : function(){ _this = this; var self = _this.self = $("#" + _this.id); // 添加里面的样式 for (var i in _this.css) { self.css(i, _this.css[i]); } return _this; }, /** * Returns the id of this component or automatically generates and * returns an id if an id is not defined yet:

     * 'ext-comp-' + (++UC.Component.AUTO_ID)
     * 
* @return {String} id */ getId : function(){ return this.id || (this.id = 'ext-comp-' + (++UC.Component.AUTO_ID)); }, /** * Show this component. Listen to the '{@link #beforeshow}' event and return * false to cancel showing the component. Fires the '{@link #show}' * event after showing the component. * @return {UC.Component} this */ show : function(){ if(this.fireEvent('beforeshow', this) !== false){ this.hidden = false; if(this.autoRender){ this.render(UC.isBoolean(this.autoRender) ? UC.getBody() : this.autoRender); } if(this.rendered){ this.onShow(); } this.fireEvent('show', this); } return this; }, /** * Hide this component. Listen to the '{@link #beforehide}' event and return * false to cancel hiding the component. Fires the '{@link #hide}' * event after hiding the component. Note this method is called internally if * the component is configured to be {@link #hidden}. * @return {UC.Component} this */ hide : function(){ this.self.hide(); } }; (function(){ var constants = UC.util.Constants; var self = null; function onRender(btnObj) { var textname = btnObj.textname || btnObj.text; btnObj.text = lang[btnObj.text] || btnObj.text; var html = '
' + ''+btnObj.text+'' + '
'; $("#" + btnObj.appendTo).append(html); }; UC.Button = UC.extend(UC.Component, { /** 在dom上的id */ text : "", /** 为了能动态切换国际语言 */ textname : "", /** 这里有 disabled || normal || active 灰色不可点 || 正常 || 按下触发 */ state : constants.STATE_NORMAL, xtype : 'Button', /** 要添加的样式 这里主要做的还是定位 */ css : {}, // Initialze Button initComponent : function () { UC.Button.superclass.initComponent.call(this); this.render(); self = this.self; this.addEventListener(); this.stateFn(this.state); }, // Private addEventListener : function () { // When the menu state is disable, do nothing if (this.stateFn() === constants.STATE_DISABLED) { return; } for (var e in this.listeners) { // Add the event listener if (typeof this.listeners[e] === "function") { var _this = this; // 对传进来的事件进行绑定 并回调 self[e](function(event){ _this.listeners[event.type].call(_this, event); }) } } }, // Private render : function () { onRender(this); UC.Button.superclass.render.call(this); }, /** * set or get Button text */ text : function (value) { return value ? this.text = value : this.text; }, /** * Show Menu * @returns Button */ show : function () { return self.show(); }, /** * hide Menu * @returns Button */ hide : function () { return self.hide(); }, /** * set or get the button state * * @param state active | normal | disabled * @returns */ stateFn : function (state) { // Get state if (state === undefined) { return this.state; } // When set state wrong parameter if (!String.eqs(state, constants.STATE_ACTIVE) && !String.eqs(state, constants.STATE_DISABLED) && !String.eqs(state, constants.STATE_NORMAL)) { throw new Error("state parameter error."); } // Set state this.state = state; self.attr("class", "button-l button-" + state); return state; } }) })();

由于时间原因,我只做一个框架,和一个Button组件,至于其他还UI组件具体实现可以参考Button 自己实现 希望对web开发的你有用
有问题可以联系我373298996 并注明Ext UI

你可能感兴趣的:(ext,ui,prototype,javascript)