RIAEasy之基础包(二)——Destroyable重构

RIAEasy之基础包(二)——Destroyable重构

Destroyable重构是_rias.js中比较重要的一项内容,完成了dijit/Destroyable的重构,使之实现了Owner属性,并能够用于非dijit类。

	rias.destroy = function(/*riasWidget|dijit|DOMNode|String*/ node, preserveDom){
		var w = rias.by(node);
		if(w){
			if(!w._beingDestroyed){
				if(!w._destroyed){
					if(w.destroyRecursive){
						w.destroyRecursive(preserveDom);
					}else if(w.destroy){
						w.destroy(preserveDom)
					}else if(w.remove){
						w.remove(preserveDom)
					}
					w._destroyed = true;
				}
				w._beingDestroyed = true;
			}
		}else{
			w = rias.byDomId(node);
			if(rias.isDomNode(w)){
				dojo.destroy(w);
			}
		}
	};

	rias.removeChild = function(parent, child){
		if(child._riaswParent == parent){
			//console.debug(parent, child);
			delete child._riaswParent;
		}
		if(!rias.isDijit(child)){
			return;
		}
		有些控件在 removeChild() 的时候会 destroy(), 比如 StackContainer,所以不能 removeChild()
		///重写 StackContainer.removeChild 和 destroyDescendants
		if(rias.isDijit(parent)){
			if(parent.removeChild){
				parent.removeChild(child);
			}else{
				(parent.containerNode || parent.domNode).removeChild(child.domNode);
			}
		}else if(rias.isDomNode(parent)){
			parent.removeChild(child.domNode);
		}else{///其它,仅仅是 Object
			///暂时没有什么可以处理的。
		}
	};
	rias.orphan = function(handle){
		var i;
		///一般情况下,orphan() 之前有可能已经 destroy domNode,所以不能在这里 removeChilde。移到 destroy() 和 destroyDescendants() 中处理。
		//if(handle._riaswParent){
		//	rias.removeChild(handle._riaswParent, handle);
		//}
		if(handle._riaswOwner){
			///_riaswOwner 不是 Parent,不应该 removeChild
			//if(rias.isDijit(handle)){
			//	rias.removeChild(handle._riaswOwner, handle);
			//}
			i = rias.indexOfByAttr(handle._riaswOwner._riaswChildren, handle, "_handle");
			if(i >= 0){
				handle._riaswOwner._riaswChildren[i]._remove.remove();
				handle._riaswOwner._riaswChildren.splice(i, 1);
			}
			delete handle._riaswOwner;
		}
		return handle;
	};
	rias.own = function(parent, handle, position){
		if(parent.own){
			if(position){
				return parent.own(position, handle);///[]
			}else{
				return parent.own(handle);///[]
			}
		}
		return [handle];
	};

	if(rias.hostBrowser){
		rias.setObject("rias.Destroyable", Destroyable);
	}else{
		Destroyable = rias.declare("rias.Destroyable", null, {});
	}
	Destroyable.extend({
		destroy: function(/*Boolean*/ preserveDom){
			var self = this;
			self._beingDestroyed = true;
			if(!self._destroying){
				self._destroying = true;
				rias.forEach(self._riaswChildren, function(handle){
					handle = handle._handle;
					if(handle._riaswOwner && handle._riaswOwner != self){
						rias.removeChild(self, handle);
					}else if(handle.destroy){
						handle.destroy(preserveDom);
					}
				});
				self.orphan();
				if(riasPage && riasPage.removeWidget){
					riasPage.removeWidget(self.id);
				}
				if(self._riaswModule && self._riaswModule[self._riaswIdOfModule]){
					delete self._riaswModule[self._riaswIdOfModule];
				}
			}
			self._destroyed = true;
			self._destroying = false;
		},

		_setOwnerAttr: function(owner){
			if(rias.isFunction(owner.isInstanceOf) && owner.isInstanceOf(Destroyable)){
				this._set("_riaswOwner", owner);
				owner.own(this);
			}else{
				throw new Error("The owner of " + owner + " is not isInstanceOf rias.Destroyable.");
			}
		},
		_getOwnerAttr: function(){
			return this._riaswOwner;
		},
		orphan: function(){
			return rias.orphan(this);
		},
		own: function(position, handles){
			var self = this,
				i, _i,
				hds,
				cleanupMethods = [
					"destroyRecursive",
					"destroy",
					"remove"
				];
			if(!self._riaswChildren){
				self._riaswChildren = [];
			}
			if(!position || rias.isNumber(position)){
				i = (position < self._riaswChildren.length ? position : self._riaswChildren.length);
				hds = rias.toArray(arguments, 1);
			}else if(position === "first"){
				i = 0;
				hds = rias.toArray(arguments, 1);
			}else{
				i = self._riaswChildren.length;
				hds = arguments;
			}

			rias.forEach(hds, function(handle){
				// When this.destroy() is called, destroy handle.  Since I'm using aspect.before(),
				// the handle will be destroyed before a subclass's destroy() method starts running, before it calls
				// this.inherited() or even if it doesn't call this.inherited() at all.  If that's an issue, make an
				// onDestroy() method and connect to that instead.
				var destroyMethodName;
				var odh = {
					_handle: handle,
					_remove: rias.before(self, "destroy", function (preserveDom){
						if(handle._riaswParent){
							rias.removeChild(handle._riaswParent, handle);
						}
						if(destroyMethodName === "remove" || destroyMethodName === "close"){
							rias.hitch(handle, self.orphan)();
						}
						handle[destroyMethodName](preserveDom);
					})
				};
				if(rias.isRiasw(handle)){
					rias.hitch(handle, self.orphan)();
					handle._riaswOwner = self;
					self._riaswChildren.splice(i, 0, odh);
					i++;
				}

				// Callback for when handle is manually destroyed.
				var hdhs = [];
				function onManualDestroy(){
					odh._remove.remove();
					rias.forEach(hdhs, function(hdh){
						hdh._remove.remove();
					});
				}

				// Setup listeners for manual destroy of handle.
				// Also computes destroyMethodName, used in listener above.
				if(handle.then){
					// Special path for Promises.  Detect when Promise is resolved, rejected, or
					// canceled (nb: cancelling a Promise causes it to be rejected).
					destroyMethodName = "cancel";
					handle.then(onManualDestroy, onManualDestroy);
				}else{
					// Path for other handles.  Just use AOP to detect when handle is manually destroyed.
					rias.forEach(cleanupMethods, function(cleanupMethod){
						if(typeof handle[cleanupMethod] === "function"){
							if(!destroyMethodName){
								// Use first matching method name in above listener (prefer destroyRecursive() to destroy())
								destroyMethodName = cleanupMethod;
							}
							hdhs.push({
								_handle: handle,
								_remove: rias.after(handle, cleanupMethod, onManualDestroy, true)
							});
						}
					});
				}
			}, self);

			return hds;		// handle
		}
	});


从代码中可以看出,Destroyable增加了_riaswOwner_riaswChildren两个属性,和orphan方法,同时扩展了原有的own方法。

可能很多同学会有疑问,这样做有什么好处呢?

首先需要说明的是,如果你只是在做HTML,或者你的应用里面不涉及运行期动态创建、销毁,那么的确可以沿用dojo原有的Destroyable而无需扩展,dijit会在destroy的时候正确地销毁。如果你准备做SPA,或者涉及到运行期动态创建、销毁,特别是一个widget还要移动其dom结构,比如drag/dropdock,那么,问题来了:当某个widget在运行期dock到一个不是其创建者(Owner)的另一个dom节点上(Parent),而这个节点(Parent)在某个时刻要销毁,_WidgetBase会同时也销毁掉这个widgetdomNode,那么原来引用这个widget的东西(Owner)可能会出现错误,因为widgetdomNode被销毁了!

所以,解决的办法就是把OwnerParent明确地标示出来,并分离,分别处理。在destroy的时候,我们只销毁属于自身创建的东西,即 Owner 是自己,对于Parent是自己,但Owner不是自己的,则只是做一个 removeChild 操作。

至于Parent相关部分是怎样的,将在后面解析,毕竟这里是共用包,不包含dom结构。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RIAEasy - A lightweight, modular, mobile-ready, data-driven for single-page-application.模块化、轻量的富客户/单页应用框架。 RIAEasy是一个单页 Web 应用 (single-page application 简称为 SPA)设计平台。旨在实现RIA/SPA应用的快速、高质量开发,实现模块化开发,实现移动、桌面系统统一的跨浏览器开发。可以使用RIAStudio在线可视化设计器。 RIAEasy基于webComponent概念设计,括一整套基础控件,具有良好的运行期动态适应性;实现了完全的前端渲染,数据驱动,前后分离,无需后端服务器生成页面;实现了主题(theme)分离,可以自由换肤;同时支持桌面和移动端。目前已经基本可以替代EasyUI、ExtJS(Sencha),特别适合于webMIS和webApp应用。 RIAEasy基于dojo构建(dojo 1.10),支持HTML5、CSS3;采用AMD(异步模块定义)加载,封装并扩展了dojo、dijit和部分dojox模块,封装并扩展了dgrid、gridx和Eclipse orion 7的在线编辑等控件。 RIAEasy是面向跨平台的单页应用设计平台,与传统的网页设计模式差别较大,反而更接近传统的C/S桌面应用设计模式。尽管RIAEasy也可以用来快速设计传统的网页,但这显然不是其真正的优势。正如RIAEasy的名称已经表明的,这是一个用来做RIA的工具。如果您做过C/S桌面应用,用过Delphi、C Builder、VisualStudio这些工具,那么就更容易理解RIAEasy。 标签:RIAEasy

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值