AS3:如何访问 children of children of children?
AS3: How to access children of children of children?
是否有更好(更快、更短或更整洁)的方法来访问 3 层或更深的 child 精灵 (object)?如果child人都已经有了名字,而且你知道名字。有没有比我在下面编写的代码更好的方法?
var mySprite:DisplayObjectContainer = layerASprite.getChildByName("layerA") 作为 DisplayObjectContainer;
mySprite = mySprite.getChildByName("layerB") 作为 DisplayObjectContainer;
mySprite.getChildByName("layerC").y = 200;
如果它们是唯一的,您可以以静态 class variables/methods:
的形式创建一个 "global" 注册表
package
{
public class Registry
{
static private var hash:Object = new Object;
static public function register(name:String, target:DisplayObject):void
{
hash[name] = target;
}
static public function access(name:String):DisplayObject
{
return hash[name];
}
}
}
用法:
// Any MovieClip, frame 1 or class constructor.
import Registry;
Registry.register("deepChild", this);
// From any other place.
import Registry;
Registry.access("deepChild").y = 200;
或者,您可以使用一种通过单个字符串参数挖掘子项的子项的方法:
function offSpring(path:String):DisplayObject
{
var aSplit:Array = path.split(".");
var result:DisplayObject = this;
while (aSplit.length)
{
var aParent:DisplayObjectContainer = result as DisplayObjectContainer;
if (!aParent) return null;
result = aParent.getChildByName(aSplit.shift());
}
return result;
}
用法:
offSpring("layerA.layerB.layerC").y = 200;
因为我不是静态属性的忠实粉丝所以我也建议递归搜索:
public function findChild(d:DisplayObject, n:String):DisplayObject {
var dc:DisplayObjectContainer = d as DisplayObjectContainer; if (!dc) return null;
for (var i:int = 0; i < dc.numChildren; i++){
var ch:DisplayObject = dc.getChildAt(i);
if (ch.name == n || (ch = findChild(ch, n))) return ch;
}return null;
}
然后你可以简单地输入:
var d:DisplayObject = findChild(stage, "childName");
在舞台上的任何地方找到名字为 childName
的第一个 child。
刚写的,测试了一次,希望没问题
优点:
- 您无需执行任何其他步骤即可使用此方法。您甚至不需要为您搜索的 child 的容器命名。
- 您可以在任何
DisplayObjectContainer
处开始搜索。
- 如果您在某个时候决定需要将 child 表单容器
A
移动到容器 B
如果它仍然是相同的分支并具有唯一的名称。
缺点:
- 这可能会很昂贵,尤其是如果您有广泛的分支机构。
- 您需要确保 child 的名称在搜索到的分支中是唯一的。
更复杂的版本
因为搜索 children 通常可以直接 child 给定容器或更近的级别,您可以一次搜索 child 一个级别,尽管这有点棘手。例如我的 alpha 版本:
/**
* Perform parallel/sprial recursive search in this container to find child with given name.
* This means that this function will first check names of all child of this container and and then go to deeper level.
* In other words, no element will be tested on level x+1 if not all elements were tested on level x.
* This is true for all levels until whole tree is exhausted. This method is using token argument for such functionallity.
* @param n name of child element to be found.
* @param t token passed internally for sipral search. You should not specify this if you want the function to search a whole tree.
* The token has only single value which is basically a desired level at which child should be searched for.
* Level 1 means this function will only check its own childrens, level 2 means that only childs of childs of this container will be checked and so one.
* However note that if you specify a token with some level, only that single level will be searched.
* On the other hand if given token is null, this will check childs on level 1, then level 2, 3... and it will countinue until deepest level has been reached.
* @return nearest child with specified name or null if no child with given name found.
*/
public function findChild(n:String, t:SearchToken = null, ind:String = ""):SGLElement {
ind += " ";
var r:Boolean = (t) ? false : true; //is this call root of search.
t = (t) ? t.offL( -1) : new SearchToken(0); //create new token if not given or decrement current token value.
//trace(ind + "F", this.name, ":", t);
//if (!t) t = new SearchToken(0);
//--t.l;
var cl:SearchToken = new SearchToken(t.l); //current search level.
var exc:int = 0; //exhausted childrens.
if(t.l == 0){//search own children
for (var i:int = 0; i < _childs.length; i++) { //trace(ind + " c", _childs[i].name);
if (_childs[i].name == n) return _childs[i]; }
if (r) ++cl.l; else return null;
}
while( cl.l > 0){
if (exc >= _childs.length) { t.l = -1; return null;}
for (i = 0; i < _childs.length; i++) {
//trace(ind + "ch", t,":", i, _childs[i].name, _childs[i]);
if (!(_childs[i] as SGLElementContainer)) continue;
//trace(ind + "t", t, i);
t.l = cl.l;
var e:SGLElement = SGLElementContainer(_childs[i]).findChild(n, t, ind);
//++cl.l;
if (e) return e;
else if (t.l < 0) exc++;
}
//trace(ind + "END_LEVEL>>>>", t);
if (!r) return null;
//t.l = cl.l;
++cl.l;
}
return null;
}
令牌class
package adnss.common.utils
{
public class SearchToken
{
/**Current level**/
public var l:int;
public function SearchToken(levelValue:int) {l = levelValue;}
public function toString():String {return String(l);}
/**Set level value and return this token instance.**/
public function setL(v:int):SearchToken { l = v; return this; }
/**Add given offset value to level value and return this token instance.**/
public function offL(v:int):SearchToken { l += v; return this;}
}
}
我注意到我不知道此类搜索的技术名称是什么,所以我给了它自己的名字,并且此方法不用于显示列表,因此您需要对其进行调整。解释起来有点困难,但如果您对此有任何疑问,请随时提问。
是否有更好(更快、更短或更整洁)的方法来访问 3 层或更深的 child 精灵 (object)?如果child人都已经有了名字,而且你知道名字。有没有比我在下面编写的代码更好的方法?
var mySprite:DisplayObjectContainer = layerASprite.getChildByName("layerA") 作为 DisplayObjectContainer;
mySprite = mySprite.getChildByName("layerB") 作为 DisplayObjectContainer;
mySprite.getChildByName("layerC").y = 200;
如果它们是唯一的,您可以以静态 class variables/methods:
的形式创建一个 "global" 注册表package
{
public class Registry
{
static private var hash:Object = new Object;
static public function register(name:String, target:DisplayObject):void
{
hash[name] = target;
}
static public function access(name:String):DisplayObject
{
return hash[name];
}
}
}
用法:
// Any MovieClip, frame 1 or class constructor.
import Registry;
Registry.register("deepChild", this);
// From any other place.
import Registry;
Registry.access("deepChild").y = 200;
或者,您可以使用一种通过单个字符串参数挖掘子项的子项的方法:
function offSpring(path:String):DisplayObject
{
var aSplit:Array = path.split(".");
var result:DisplayObject = this;
while (aSplit.length)
{
var aParent:DisplayObjectContainer = result as DisplayObjectContainer;
if (!aParent) return null;
result = aParent.getChildByName(aSplit.shift());
}
return result;
}
用法:
offSpring("layerA.layerB.layerC").y = 200;
因为我不是静态属性的忠实粉丝所以我也建议递归搜索:
public function findChild(d:DisplayObject, n:String):DisplayObject {
var dc:DisplayObjectContainer = d as DisplayObjectContainer; if (!dc) return null;
for (var i:int = 0; i < dc.numChildren; i++){
var ch:DisplayObject = dc.getChildAt(i);
if (ch.name == n || (ch = findChild(ch, n))) return ch;
}return null;
}
然后你可以简单地输入:
var d:DisplayObject = findChild(stage, "childName");
在舞台上的任何地方找到名字为 childName
的第一个 child。
刚写的,测试了一次,希望没问题
优点:
- 您无需执行任何其他步骤即可使用此方法。您甚至不需要为您搜索的 child 的容器命名。
- 您可以在任何
DisplayObjectContainer
处开始搜索。 - 如果您在某个时候决定需要将 child 表单容器
A
移动到容器B
如果它仍然是相同的分支并具有唯一的名称。
缺点:
- 这可能会很昂贵,尤其是如果您有广泛的分支机构。
- 您需要确保 child 的名称在搜索到的分支中是唯一的。
更复杂的版本
因为搜索 children 通常可以直接 child 给定容器或更近的级别,您可以一次搜索 child 一个级别,尽管这有点棘手。例如我的 alpha 版本:
/**
* Perform parallel/sprial recursive search in this container to find child with given name.
* This means that this function will first check names of all child of this container and and then go to deeper level.
* In other words, no element will be tested on level x+1 if not all elements were tested on level x.
* This is true for all levels until whole tree is exhausted. This method is using token argument for such functionallity.
* @param n name of child element to be found.
* @param t token passed internally for sipral search. You should not specify this if you want the function to search a whole tree.
* The token has only single value which is basically a desired level at which child should be searched for.
* Level 1 means this function will only check its own childrens, level 2 means that only childs of childs of this container will be checked and so one.
* However note that if you specify a token with some level, only that single level will be searched.
* On the other hand if given token is null, this will check childs on level 1, then level 2, 3... and it will countinue until deepest level has been reached.
* @return nearest child with specified name or null if no child with given name found.
*/
public function findChild(n:String, t:SearchToken = null, ind:String = ""):SGLElement {
ind += " ";
var r:Boolean = (t) ? false : true; //is this call root of search.
t = (t) ? t.offL( -1) : new SearchToken(0); //create new token if not given or decrement current token value.
//trace(ind + "F", this.name, ":", t);
//if (!t) t = new SearchToken(0);
//--t.l;
var cl:SearchToken = new SearchToken(t.l); //current search level.
var exc:int = 0; //exhausted childrens.
if(t.l == 0){//search own children
for (var i:int = 0; i < _childs.length; i++) { //trace(ind + " c", _childs[i].name);
if (_childs[i].name == n) return _childs[i]; }
if (r) ++cl.l; else return null;
}
while( cl.l > 0){
if (exc >= _childs.length) { t.l = -1; return null;}
for (i = 0; i < _childs.length; i++) {
//trace(ind + "ch", t,":", i, _childs[i].name, _childs[i]);
if (!(_childs[i] as SGLElementContainer)) continue;
//trace(ind + "t", t, i);
t.l = cl.l;
var e:SGLElement = SGLElementContainer(_childs[i]).findChild(n, t, ind);
//++cl.l;
if (e) return e;
else if (t.l < 0) exc++;
}
//trace(ind + "END_LEVEL>>>>", t);
if (!r) return null;
//t.l = cl.l;
++cl.l;
}
return null;
}
令牌class
package adnss.common.utils
{
public class SearchToken
{
/**Current level**/
public var l:int;
public function SearchToken(levelValue:int) {l = levelValue;}
public function toString():String {return String(l);}
/**Set level value and return this token instance.**/
public function setL(v:int):SearchToken { l = v; return this; }
/**Add given offset value to level value and return this token instance.**/
public function offL(v:int):SearchToken { l += v; return this;}
}
}
我注意到我不知道此类搜索的技术名称是什么,所以我给了它自己的名字,并且此方法不用于显示列表,因此您需要对其进行调整。解释起来有点困难,但如果您对此有任何疑问,请随时提问。