您的位置:首页 > 产品设计 > UI/UE

YUI3组件框架之plugin

2013-10-09 10:05 155 查看

plugin相关源码分析:

plugin功能包括如下几个模块, 简单分析如下:

pluginhost-base

维护对象 this._plugins = {};

并提供方法: plug、unplug、hasplug、_destroyPlugins、_initPlugins

plug: 初始化插件实例,并与host进行关联  

if (Plugin && !L.isFunction(Plugin)) {
config = Plugin.cfg;
Plugin = Plugin.fn;
}

// Plugin should be fn by now
if (Plugin && Plugin.NS) {
ns = Plugin.NS;

config = config || {};
config.host = this;

if (this.hasPlugin(ns)) {
// Update config
if (this[ns].setAttrs) {
this[ns].setAttrs(config);
}
} else {
// Create new instance
this[ns] = new Plugin(config);
this._plugins[ns] = Plugin;
}
}


_initPlugins: 调用模块 pluginhost-config 中的_initConfigPlugins(config);

根据this._classes(原型链上的constructor对象)上的静态属性 _PLUG and _UNPLUG, 来初始化plugin

通过widget初始化时的config配置, 来初始化plugin

在YUI Widget体系中base-core模块用来初始化插件, 初始化所有ext和ATTRS后调用  

PluginHost.prototype.\_initConfigPlugins = function(config) {

// Class Configuration
var classes = (this._getClasses) ? this._getClasses() : [this.constructor],
plug = [],
unplug = {},
constructor, i, classPlug, classUnplug, pluginClassName;
// TODO: Room for optimization. Can we apply statically/unplug in same pass?
for (i = classes.length - 1; i >= 0; i--) {
constructor = classes[i];

classUnplug = constructor._UNPLUG;
if (classUnplug) {
// subclasses over-write
Y.mix(unplug, classUnplug, true);
}

classPlug = constructor._PLUG;
if (classPlug) {
// subclasses over-write
Y.mix(plug, classPlug, true);
}
}

for (pluginClassName in plug) {
if (plug.hasOwnProperty(pluginClassName)) {
if (!unplug[pluginClassName]) {
this.plug(plug[pluginClassName]);
}
}
}

// User Configuration
if (config && config.plugins) {
this.plug(config.plugins);
}
};  


pluginhost-config

_initConfigPlugins

静态方法: plug、unplug

提供给Y.Base引用

base-pluginhost

mixin Base and PluginHost, 即:

Y.mix(Base, PluginHost, false, null, 1);
Base.plug = PluginHost.plug;
Base.unplug = PluginHost.unplug;  


plugin

继承Y.Base . 提供AOP的一系列方法, 如:

doBefore: function(strMethod, fn, context) {
var host = this.get("host"), handle;
if (strMethod in host) { // method
handle = this.beforeHostMethod(strMethod, fn, context);
} else if (host.on) { // event
handle = this.onHostEvent(strMethod, fn, context);
}
return handle;
},
doAfter: function() {
...
},
onHostEvent: function() {
var handle = this.get("host").on(type, fn, context || this);
this._handles.push(handle);
return handle;
},
afterHostEvent: function() {
...
},
beforeHostMethod: function() {
...
},
afterHostMethod: function() {
...
} 


如何写一个插件

1、 任何简单对象即可成为一个简单插件, 如:

function NodeDrag(config) {
var host = config.host;
drag(host);
}
function drag(host) {
...
}


2、YUI的Plugin基类提供了基于事件的AOP机制支持,可以通过继承它在不影响原有代码逻辑前提下,通过对代码执行过程的控制,达到改变原有代码逻辑或者增加插件功能的效果, 如:

function NodeDrag() {
NodeDrag.superclass.constructor.apply(this, arguments);
}
Y.extend(NodeDrag, Y.Plugin.Base, {
drag: function() {
...
}
});


使用插件的几种方式

给一个node节点添加一个插件

1、使用Base的静态方法, 实际调用的是pluginhost-config里面的plug方法

Y.Base.plug(Y.one('#foo'), NodeDrag, config);


2、node对象和继承了Y.Base对象的实例都可以通过实例直接调用plug方法使用插件

Y.one('#foo').plug(NodeDrag, config);


3、具体widget

function Widget() {}
Y.extend(Widget, Y.Base, {
initializer: function() {
...
}
});
var w = new Widget({plugins: NodeDrag});
//var w = new Widget({plugins: [NodeDrag, ..]});
//var w = new Widget({plugins: {fn: NodeDrag, cfg: {} });
//w.plug(NodeDrag, cfg);


  

在一些情况,为了让调用者不必过多的关心实现细节的时候,也将插件的初始化放到具体widget的实现中, 如:

Widget.ATTRS = {
drag: {
value: false
}
};
Y.extend(Widget, Y.Base, {
initializer: function() {
if(this.get('drag')) {
this.plug(NodeDrag, cfg);
}
}
});


插件的一些优势和适合的场景

插件一般是基于host开发的扩展功能, 用以对host功能的增强,如一些动画效果、也类如dota游戏中一些英雄所具有的各种技能等

插件机制能对复杂功能进行更好的抽象, 减少代码逻辑的耦合

如,在代码中由于加入一个功能,会涉及到很多代码片段加入if else 判断逻辑, 那么可以考虑将这个功能作为一个plugin增强, 使用AOP的方式与原来代码逻辑关联起来

通过host进行统一的入口管理
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: