YUI3组件框架之plugin
plugin相关源码分析:
plugin功能包括如下几个模块, 简单分析如下:
pluginhost-base
维护对象 this._plugins = {};
并提供方法: plug、unplug、hasplug、_destroyPlugins、_initPlugins
plug: 初始化插件实例,并与host进行关联
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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后调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | 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
1 2 3 4 5 | mixin Base and PluginHost, 即: Y.mix(Base, PluginHost, false , null , 1); Base.plug = PluginHost.plug; Base.unplug = PluginHost.unplug; |
plugin
继承Y.Base . 提供AOP的一系列方法, 如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | 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、 任何简单对象即可成为一个简单插件, 如:
1 2 3 4 5 6 7 | function NodeDrag(config) { var host = config.host; drag(host); } function drag(host) { ... } |
2、YUI的Plugin基类提供了基于事件的AOP机制支持,可以通过继承它在不影响原有代码逻辑前提下,通过对代码执行过程的控制,达到改变原有代码逻辑或者增加插件功能的效果, 如:
1 2 3 4 5 6 7 8 | function NodeDrag() { NodeDrag.superclass.constructor.apply( this , arguments); } Y.extend(NodeDrag, Y.Plugin.Base, { drag: function () { ... } }); |
使用插件的几种方式
给一个node节点添加一个插件
1、使用Base的静态方法, 实际调用的是pluginhost-config里面的plug方法
1 | Y.Base.plug(Y.one( '#foo' ), NodeDrag, config); |
2、node对象和继承了Y.Base对象的实例都可以通过实例直接调用plug方法使用插件
1 | Y.one( '#foo' ).plug(NodeDrag, config); |
3、具体widget
1 2 3 4 5 6 7 8 9 10 | 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的实现中, 如:
1 2 3 4 5 6 7 8 9 10 11 12 | 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进行统一的入口管理
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET制作智能桌面机器人:结合BotSharp智能体框架开发语音交互
· 软件产品开发中常见的10个问题及处理方法
· .NET 原生驾驭 AI 新基建实战系列:向量数据库的应用与畅想
· 从问题排查到源码分析:ActiveMQ消费端频繁日志刷屏的秘密
· 一次Java后端服务间歇性响应慢的问题排查记录
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(四):结合BotSharp
· 一个基于 .NET 开源免费的异地组网和内网穿透工具
· 《HelloGitHub》第 108 期
· Windows桌面应用自动更新解决方案SharpUpdater5发布
· 我的家庭实验室服务器集群硬件清单