一款类似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;
}
})

})();


由于时间原因,我只做一个框架,和一个Button组件,至于其他还UI组件具体实现可以参考Button 自己实现 希望对web开发的你有用
有问题可以联系我373298996 并注明Ext UI
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值