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;} 
    }

}

我注意到我不知道此类搜索的技术名称是什么,所以我给了它自己的名字,并且此方法不用于显示列表,因此您需要对其进行调整。解释起来有点困难,但如果您对此有任何疑问,请随时提问。