/_src/core/zepto.ui.js
https://github.com/leaven/gmu · JavaScript · 360 lines · 181 code · 24 blank · 155 comment · 39 complexity · cfc82b3e473e7c9dfd3b7466f042f4b8 MD5 · raw file
- /**
- * @file
- * @name UI 基类
- * @short Zepto UI
- * @desc 所有UI组件的基类,通过它可以简单的快速的创建新的组件。
- * @import core/zepto.js, core/zepto.extend.js
- */
- (function($, undefined) {
- $.ui = $.ui || {
- version: '2.0',
- guid: _guid,
- /**
- * @name $.ui.define
- * @grammar $.ui.define(name, data[, superClass]) ⇒ undefined
- * @desc 定义组件,
- * - ''name'' 组件名称
- * - ''data'' 对象,设置此组件的prototype。可以添加属性或方法
- * - ''superClass'' 基类,指定此组件基于哪个现有组件,默认为Widget基类
- * **示例:**
- * <code type="javascript">
- * $.ui.define('helloworld', {
- * _data: {
- * opt1: null
- * },
- * enable: function(){
- * //...
- * }
- * });
- * </code>
- *
- * **定义完后,就可以通过以下方式使用了**
- *<code type="javascript">
- * var instance = $.ui.helloworld({opt1: true});
- * instance.enable();
- *
- * //或者
- * $('#id').helloworld({opt1:true});
- * //...later
- * $('#id').helloworld('enable');
- * </code>
- *
- * **Tips**
- * 1. 通过Zepto对象上的组件方法,可以直接实例话组件, 如: $('#btn').button({label: 'abc'});
- * 2. 通过Zepto对象上的组件方法,传入字符串this, 可以获得组件实例,如:var btn = $('#btn').button('this');
- * 3. 通过Zepto对象上的组件方法,可以直接调用组件方法,第一个参数用来指定方法名,之后的参数作为方法参数,如: $('#btn').button('setIcon', 'home');
- * 4. 在子类中,如覆写了某个方法,可以在方法中通过this.$super()方法调用父级方法。如:this.$super('enable');
- */
- define: function(name, data, superClass) {
- if(superClass) data.inherit = superClass;
- var Class = $.ui[name] = _createClass(function(el, options) {
- var obj = _createObject(Class.prototype, {
- _id: $.parseTpl(tpl, {
- name: name,
- id: _guid()
- })
- });
- obj._createWidget.call(obj, el, options,Class.plugins);
- return obj;
- }, data);
- return _zeptoLize(name, Class);
- }
- };
- var id = 1,
- tpl = '<%=name%>-<%=id%>',
- uikey = 'gmu-widget';
-
- /**
- * generate guid
- */
- function _guid() {
- return id++;
- };
- function _createObject(proto, data) {
- var obj = {};
- Object.create ? obj = Object.create(proto) : obj.__proto__ = proto;
- return $.extend(obj, data || {});
- }
- function _createClass(Class, data) {
- if (data) {
- _process(Class, data);
- $.extend(Class.prototype, data);
- }
- return $.extend(Class, {
- plugins: [],
- register: function(fn) {
- if ($.isObject(fn)) {
- $.extend(this.prototype,fn);
- return;
- }
- this.plugins.push(fn);
- }
- });
- }
- /**
- * handle inherit & _data
- */
- function _process(Class, data) {
- var superClass = data.inherit || _widget,
- proto = superClass.prototype,
- obj;
- obj = Class.prototype = _createObject(proto, {
- $factory: Class,
- $super: function(key) {
- var fn = proto[key];
- return $.isFunction(fn) ? fn.apply(this, $.slice(arguments, 1)) : fn;
- }
- });
- obj._data = $.extend({}, proto._data, data._data);
- delete data._data;
- return Class;
- }
- /**
- * 强制setup模式
- * @grammar $(selector).dialog(opts);
- */
- function _zeptoLize(name) {
- $.fn[name] = function(opts) {
- var ret, obj,args = $.slice(arguments, 1);
- $.each(this,function(i,el){
- obj = $(el).data(uikey + name) || $.ui[name](el, $.extend($.isPlainObject(opts) ? opts : {},{
- setup: true
- }));
- if ($.isString(opts)) {
- ret = $.isFunction(obj[opts]) && obj[opts].apply(obj, args);
- if (opts == 'this' || ret !== obj && ret !== undefined) {
- return false;
- }
- ret = null;
- }
- });
- //ret 为真就是要返回ui实例之外的内容
- //obj 'this'时返回
- //其他都是返回zepto实例
- return ret || (opts == 'this' ? obj : this);
- };
- }
- /**
- * @name widget基类
- * @desc GMU所有的组件都是此类的子类,即以下此类里面的方法都可在其他组建中调用。
- */
- var _widget = function() {};
- $.extend(_widget.prototype, {
- _data: {
- status: true
- },
- /**
- * @name data
- * @grammar data(key) ⇒ value
- * @grammar data(key, value) ⇒ value
- * @desc 设置或者获取options, 所有组件中的配置项都可以通过此方法得到。
- * @example
- * $('a#btn').button({label: '按钮'});
- * console.log($('a#btn').button('data', 'label'));// => 按钮
- */
- data: function(key, val) {
- var _data = this._data;
- if ($.isObject(key)) return $.extend(_data, key);
- else return !$.isUndefined(val) ? _data[key] = val : _data[key];
- },
- /**
- * common constructor
- */
- _createWidget: function(el, opts,plugins) {
- if ($.isObject(el)) {
- opts = el || {};
- el = undefined;
- }
- var data = $.extend({}, this._data, opts);
- $.extend(this, {
- _el: el ? $(el) : undefined,
- _data: data
- });
- //触发plugins
- var me = this;
- $.each(plugins,function(i,fn){
- var result = fn.apply(me);
- if(result && $.isPlainObject(result)){
- var plugins = me._data.disablePlugin;
- if(!plugins || $.isString(plugins) && plugins.indexOf(result.pluginName) == -1){
- delete result.pluginName
- $.each(result,function(key,val){
- var orgFn;
- if((orgFn = me[key]) && $.isFunction(val)){
- me[key] = function(){
- me[key + 'Org'] = orgFn;
- return val.apply(me,arguments);
- }
- }else
- me[key] = val;
- })
- }
- }
- });
- // use setup or render
- if(data.setup) this._setup(el && el.getAttribute('data-mode'));
- else this._create();
- this._init();
- var me = this,
- $el = this.trigger('init').root();
- $el.on('tap', function(e) {
- (e['bubblesList'] || (e['bubblesList'] = [])).push(me);
- });
- // record this
- $el.data(uikey + this._id.split('-')[0],this);
- },
- /**
- * @interface: use in render mod
- * @name _create
- * @desc 接口定义,子类中需要重新实现此方法,此方法在render模式时被调用。
- *
- * 所谓的render方式,即,通过以下方式初始化组件
- * <code>
- * $.ui.widgetName(options);
- * </code>
- */
- _create: function() {},
- /**
- * @interface: use in setup mod
- * @param {Boolean} data-mode use tpl mode
- * @name _setup
- * @desc 接口定义,子类中需要重新实现此方法,此方法在setup模式时被调用。第一个行参用来分辨时fullsetup,还是setup
- *
- * <code>
- * $.ui.define('helloworld', {
- * _setup: function(mode){
- * if(mode){
- * //为fullsetup模式
- * } else {
- * //为setup模式
- * }
- * }
- * });
- * </code>
- *
- * 所谓的setup方式,即,先有dom,然后通过选择器,初始化Zepto后,在Zepto对象直接调用组件名方法实例化组件,如
- * <code>
- * //<div id="widget"></div>
- * $('#widget').widgetName(options);
- * </code>
- *
- * 如果用来初始化的element,设置了data-mode="true",组件将以fullsetup模式初始化
- */
- _setup: function(mode) {},
- /**
- * @name root
- * @grammar root() ⇒ value
- * @grammar root(el) ⇒ value
- * @desc 设置或者获取根节点
- * @example
- * $('a#btn').button({label: '按钮'});
- * console.log($('a#btn').button('root'));// => a#btn
- */
- root: function(el) {
- return this._el = el || this._el;
- },
- /**
- * @name id
- * @grammar id() ⇒ value
- * @grammar id(id) ⇒ value
- * @desc 设置或者获取组件id
- */
- id: function(id) {
- return this._id = id || this._id;
- },
- /**
- * @name destroy
- * @grammar destroy() ⇒ undefined
- * @desc 注销组件
- */
- destroy: function() {
- var That = this,
- $el;
- $.each(this.data('components') || [], function(id, obj) {
- obj.destroy();
- });
- $el = this.trigger('destroy').off().root();
- $el.find('*').off();
- $el.removeData(uikey).off().remove();
- this.__proto__ = null;
- $.each(this, function(key, val) {
- delete That[key];
- });
- },
- /**
- * @name component
- * @grammar component() ⇒ array
- * @grammar component(subInstance) ⇒ instance
- * @grammar component(createFn) ⇒ instance
- * @desc 获取或者设置子组件, createFn为组件构造器,必须返回组件的实例。
- */
- component: function(createFn) {
- var list = this.data('components') || this.data('components', []);
- try {
- list.push($.isFunction(createFn) ? createFn.apply(this) : createFn);
- } catch(e) {}
- return this;
- },
- /**
- * @name on
- * @grammar on(type, handler) ⇒ instance
- * @desc 绑定事件,此事件绑定不同于zepto上绑定事件,此On的this只想组件实例,而非zepto实例
- */
- on: function(ev, callback) {
- this.root().on(ev, $.proxy(callback, this));
- return this;
- },
- /**
- * @name off
- * @grammar off(type) ⇒ instance
- * @grammar off(type, handler) ⇒ instance
- * @desc 解绑事件
- */
- off: function(ev, callback) {
- this.root().off(ev, callback);
- return this;
- },
- /**
- * @name trigger
- * @grammar trigger(type[, data]) ⇒ instance
- * @desc 触发事件, 此trigger会优先把options上的事件回调函数先执行,然后给根DOM派送事件。
- * options上回调函数可以通过e.preventDefaualt()来组织事件派发。
- */
- trigger: function(event, data) {
- event = $.isString(event) ? $.Event(event) : event;
- var onEvent = this.data(event.type),result;
- if( onEvent && $.isFunction(onEvent) ){
- event.data = data;
- result = onEvent.apply(this, [event].concat(data));
- if(result === false || event.defaultPrevented){
- return this;
- }
- }
- this.root().trigger(event, data);
- return this;
- }
- });
- })(Zepto);