当前位置: 代码迷 >> JavaScript >> 一款相仿Ext的轻量级实现UI的JS框架
  详细解决方案

一款相仿Ext的轻量级实现UI的JS框架

热度:526   发布时间:2014-03-01 00:37:29.0
一款类似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('<div class="{0}">{1}</div>', 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 <tt>true</tt>, 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 <code>id</code> of this component or automatically generates and
     * returns an <code>id</code> if an <code>id</code> is not defined yet:<pre><code>
     * 'ext-comp-' + (++UC.Component.AUTO_ID)
     * </code></pre>
     * @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
     * <tt>false</tt> 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
     * <tt>false</tt> 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 <code>{@link #hidden}</code>.
     * @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 = '<div id="' + btnObj.id + '" class="button-l">'
                       + '<span class="button-r" textname="' + textname + '">'+btnObj.text+'</span>'
                   + '</div>';
        
        $("#" + 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;
    }
})

})();

1 楼 cremains 2014-02-22  
没有demo的地址呢?
2 楼 ku_sunny 2014-02-22  
cremains 写道
没有demo的地址呢?

那个Button 就是一个简单的组件demo了
3 楼 ku_sunny 2014-02-22  
具体的实例 可以通过传参new Button()一个 不过样式的先定义好
4 楼 aunox 2014-02-22  
他们说的demo是指带有网页界面和示例说明的。
  相关解决方案