nuijs
Version:
nui框架
575 lines (561 loc) • 21.1 kB
JavaScript
/**
* @author Aniu[2016-11-11 16:54]
* @update Aniu[2016-11-11 16:54]
* @version 1.0.1
* @description 组件基类
*/
Nui.define(function(require){
var template = require('./template');
var events = require('./events');
var ext = require('./extends');
var slice = Array.prototype.slice;
var callMethod = function(method, args, obj){
if(typeof method === 'function'){
//实参大于形参,最后一个实参表示id
if(args.length > method.length){
var id = args[args.length-1];
if(id && Nui.type(id, ['String', 'Number']) && obj._options.id !== id && obj.__id !== id){
return
}
}
method.apply(obj, args)
}
}
var bindComponent = function(name, elem, mod, options){
//不能重复绑定
if(elem.nui && elem.nui[name]){
return
}
var $elem = jQuery(elem), _options;
if(options === undefined){
options = $elem.data(name+'Options');
}
if((options && typeof options === 'string') || typeof options === 'number'){
if(/^{[\s\S]*}$/.test(options)){
options = eval('('+ options +')');
}
else if(_options = require(options)){
if(typeof _options === 'function'){
options = _options($elem)
}
else{
options = _options
}
}
}
if(Nui.type(options, 'Object')){
mod(Nui.extend({}, options, {
target:elem
}))
}
else{
mod({
target:elem
})
}
}
/**
* 单和双下划线开头表示私有方法或者属性,只能在内部使用,
* 单下划线继承后可重写或修改,双下划线为系统预置无法修改
* 系统预置属性方法:__id, __instances, __eventList, __parent, __component_name, __setMethod
*/
var statics = {
//实例对象唯一标记
__id:0,
//实例对象容器
__instances:{},
/*
* 将实例方法接口设置为静态方法,这样可以操作多个实例,
* 默认有 init, option, reset, destroy
* init表示初始化组件,会查询容器内包含属性为 data-组件名-options的dom元素,并调用组件
*/
__setMethod:function(apis, components){
var self = this;
Nui.each(apis, function(val, methodName){
if(self[methodName] === undefined){
self[methodName] = function(){
var self = this, name = self.__component_name, args = arguments, container = args[0],
isContainer = container && container instanceof jQuery,
mod = components[name], init = methodName === 'init';
if(name && name !== 'component' && mod){
if(isContainer){
if(init){
container.find('[data-'+name+'-options]').each(function(){
bindComponent(name, this, mod)
})
}
else{
container.find('[nui_component_'+ name +']').each(function(){
var obj, nui = this.nui;
if(nui && (obj = nui[name])){
callMethod(obj[methodName], slice.call(args, 1), obj)
}
})
}
}
else{
Nui.each(self.__instances, function(obj){
callMethod(obj[methodName], args, obj)
})
}
}
else if(name === 'component'){
var attributes = [];
Nui.each(components, function(v, k){
if(k !== 'component' && typeof v[methodName] === 'function'){
if(isContainer){
if(init){
attributes.push('[data-'+ k +'-options]')
}
else{
attributes.push('[nui_component_'+ k +']')
}
}
else{
Nui.each(v.constructor.__instances, function(obj){
callMethod(obj[methodName], args, obj)
})
}
}
})
if(attributes.length){
var matchRegexp = init ? /^data-(\w+)-options/i : /^nui_component_(\w+)/i;
container.find(attributes.join(',')).each(function(index, elem){
var attrs = elem.attributes, nui = elem.nui, obj, i = attrs.length, data = [];
while(i--){
var attr = attrs[i];
if(attr && attr.name){
var match = attr.name.match(matchRegexp);
if(match){
data.push({
name:match[1],
value:attr.value
})
}
}
}
Nui.each(data, function(v){
if(init){
bindComponent(v.name, elem, components[v.name], v.value)
}
else if(nui && (obj = nui[v.name])){
callMethod(obj[methodName], slice.call(args, 1), obj)
}
})
})
}
}
}
}
})
return self
},
_listeners:{},
//对所有实例设置默认选项
_options:{},
//创建组件模块时会调用一次,可用于在document上绑定事件操作实例
_init:jQuery.noop,
_getSize:function(selector, dir, attr){
var size = 0;
attr = attr || 'border';
dir = dir || 'tb';
if(attr === 'all'){
return (this._getSize(selector, dir) +
this._getSize(selector, dir, 'padding') +
this._getSize(selector, dir, 'margin'))
}
var group = {
l:['Left'],
r:['Right'],
lr:['Left', 'Right'],
t:['Top'],
b:['Bottom'],
tb:['Top', 'Bottom']
}
var arr = [{
border:{
l:['LeftWidth'],
r:['RightWidth'],
lr:['LeftWidth', 'RightWidth'],
t:['TopWidth'],
b:['BottomWidth'],
tb:['TopWidth', 'BottomWidth']
}
}, {
padding:group
}, {
margin:group
}];
Nui.each(arr, function(val){
if(val[attr]){
Nui.each(val[attr][dir], function(v){
var value = parseFloat(selector.css(attr+v));
size += isNaN(value) ? 0 : value
});
}
});
return size
},
_$fn:function(name, module){
jQuery.fn[name] = function(){
var args = arguments;
return this.each(function(){
var dom = this, object, options = args[0];
var execMethod = function(){
if(typeof options === 'string'){
if(options === 'options'){
object.option(args[1], args[2])
}
else if(options.indexOf('_') !== 0){
var attr = object[options];
if(typeof attr === 'function'){
attr.apply(object, slice.call(args, 1))
}
}
}
}
if(dom.nui && (object = dom.nui[name])){
execMethod()
}
else if(!object){
object = module((function(opts){
if(Nui.type(opts, 'Object')){
opts.target = dom
return opts
}
else{
return {target:dom}
}
})(options))
execMethod()
}
})
}
},
config:function(){
var args = arguments;
var len = args.length;
var attr = args[0];
if(Nui.type(attr, 'Object')){
return this._options = Nui.extend(true, this._options, attr)
}
else if(Nui.type(attr, 'String')){
if(args.length === 1){
return this._options[attr]
}
return this._options[attr] = args[1]
}
},
hasInstance:function(id){
var exist = false;
var instances = this.__instances;
if(id !== undefined){
Nui.each(instances, function(v){
if(v.__id === id || v._options.id === id){
exist = v;
return false
}
})
}
else{
for(i in instances){
return true
}
}
return exist
},
listener:function(type, callback){
var self = this;
if(type && typeof callback === 'function'){
if(!this._listeners[type]){
this._listeners[type] = []
}
this._listeners[type].push(callback)
}
return function() {
self.removeListener(type, callback);
}
},
removeListener:function(type, callback){
if(type && typeof callback === 'function'){
var listeners = this._listeners[type];
if(listeners){
var index;
Nui.each(listeners, function(cb, i){
if(callback === cb){
index = i
return false;
}
})
if(index !== undefined){
this._listeners[type] = listeners.slice(0, index).concat(listeners.slice(index+1));
if(!this._listeners[type]){
delete this._listeners[type]
}
}
}
}
}
}
return this.extend({
_static:statics,
_options:{
target:null,
//组件id,element会增加class 组件名-组件id
id:'',
//组件皮肤,element会增加class nui-组件名-皮肤名
skin:'',
//element增加一个或多个类
className:'',
onInit:null,
onReset:null,
onDestroy:null
},
_template:{
style:'<%each style%><%$index%>:<%$value%>;<%/each%>'
},
_init:function(){
this._exec()
},
_exec:jQuery.noop,
_emitListener:function(type){
var self = this;
var _class = self.constructor;
var listeners = _class._listeners[type];
if(listeners){
Nui.each(listeners, function(cb){
cb(self)
})
}
},
_jquery:function(elem){
if(typeof elem === 'function'){
elem = elem.call(this._options, this)
}
if(!elem){
return
}
if(elem instanceof jQuery){
return elem
}
return jQuery(elem)
},
_getTarget:function(){
var self = this;
if(!self.target){
var target = self._options.target;
target = self._jquery(target);
if(!target){
return
}
self.target = self._bindComponentName(target);
}
return self.target
},
_bindComponentName:function(element){
var self = this, _class = self.constructor;
var attr = 'nui_component_'+_class.__component_name;
element.attr(attr, '').each(function(){
if(!this.nui){
this.nui = {};
}
this.nui[_class.__component_name] = self
})
return element
},
_disabled:function(){
return this.target.prop('disabled')
},
_getName:function(_class, array){
var skin = Nui.trim(this._options.skin);
_class = _class || this.constructor;
if(_class.__parent){
var _pclass = _class.__parent.constructor;
var _name = _pclass.__component_name;
if(_name !== 'component'){
if(skin){
array.unshift('nui-'+_name+'-'+skin);
}
array.unshift('nui-'+_name);
return this._getName(_pclass, array)
}
}
return array
},
_tplData:function(data){
var opts = this._options,
skin = Nui.trim(opts.skin),
_class = this.constructor,
name = 'nui-' + _class.__component_name,
className = this._getName(_class, []);
className.push(name);
if(skin){
className.push(name+'-'+skin)
}
if(opts.id){
className.push(_class.__component_name + '-' + opts.id)
}
if(!data){
data = {}
}
if(opts.className){
className.push(opts.className)
}
data.className = className.join(' ');
return data
},
_event:function(){
var self = this, opts = self._options;
if(self.element && opts.events){
opts.element = self.element;
events.call(self, opts)
}
return events.call(self)
},
_on:function(type, dalegate, selector, callback, trigger){
var self = this;
if(typeof selector === 'function'){
trigger = callback;
callback = selector;
selector = dalegate;
dalegate = null;
selector = self._jquery(selector)
}
var _callback = function(e){
return callback.call(this, e, jQuery(this))
}
if(dalegate){
if(typeof selector !== 'string'){
selector = selector.selector;
if(!selector){
selector = self._options.target
}
}
dalegate.on(type, selector, _callback);
if(trigger){
dalegate.find(selector).trigger(type)
}
}
else{
selector.on(type, _callback);
if(trigger){
selector.trigger(type)
}
}
self.__eventList.push({
dalegate:dalegate,
selector:selector,
type:type,
callback:_callback
});
return self
},
_off:function(){
var self = this, _eventList = self.__eventList;
Nui.each(_eventList, function(val, key){
if(val.dalegate){
val.dalegate.off(val.type, val.selector, val.callback)
}
else{
val.selector.off(val.type, val.callback)
}
_eventList[key] = null;
delete _eventList[key]
});
self.__eventList = [];
return self
},
_delete:function(){
var self = this, _class = self.constructor;
if(self.target){
var attr = 'nui_component_'+_class.__component_name;
self.target.removeAttr(attr).each(function(){
if(this.nui){
this.nui[_class.__component_name] = null;
delete this.nui[_class.__component_name];
}
})
}
_class.__instances[self.__id] = null;
delete _class.__instances[self.__id]
},
_reset:function(){
this._off();
if(this.element){
this.element.remove();
this.element = null;
}
return this
},
_tpl2html:function(id, data){
var opts = {
openTag:'<%',
closeTag:'%>'
}
if(arguments.length === 1){
return template.render(this._template, id, opts)
}
return template.render.call(this._template, this._template[id], data, opts)
},
_callback:function(method, args){
var self = this, opts = self._options;
var callback = opts['on'+method];
if(typeof callback === 'function'){
if(args){
Array.prototype.unshift.call(args, self);
return callback.apply(opts, args);
}
return callback.call(opts, self)
}
},
option:function(opts, isOriginal){
var args = arguments;
var isdef = false;
var options;
if(args[0] === true){
isdef = true
}
else if(jQuery.isPlainObject(args[0])){
options = args[0]
isdef = args[1]
}
else if(args.length > 1 && typeof args[0] === 'string'){
options = {};
options[args[0]] = args[1]
isdef = args[2]
}
if(options||isdef){
this._options = Nui.extend(true, {}, this[isdef === true ? '_defaultOptions' : '_options'], options)
this._reset();
this._exec();
}
return this
},
on:function(name, callback){
var self = this, callbacks = {};
if(
typeof name === 'string' &&
typeof callback === 'function'
){
callbacks[name] = callback
}
else if(typeof name === 'object'){
callbacks = name
}
Nui.each(callbacks, function(v, k){
self._options['on' + k.substr(0, 1).toUpperCase() + k.substr(1)] = v
})
return this
},
reset:function(){
this.option(true);
this._callback('Reset');
return this;
},
destroy:function(){
this._delete();
this._reset();
this._callback('Destroy');
}
})
})