AS3 / Flex 4: самый практичный способ найти вложенных детей - PullRequest
3 голосов
/ 28 октября 2010

Я как бы прыгаю вперёд к некоторым вещам Flex / AIR. У меня довольно солидный опыт работы с AS3, но, учитывая внутреннюю сложность иерархии Flex (по сравнению с обычной Flash), я столкнулся с проблемой.

Давайте предположим, что у вас есть приложение, в котором почти все основано на событиях (часто). Доступ к элементам в непосредственной близости от цели события или самой цели события тривиален. Однако я пытаюсь найти наиболее практичный (читай: лучший, самый эффективный) способ найти детей, которые далеки от текущего контекста.

Я знаю, что есть такие функции, как getChildAt() и getChildByName(), но это предполагает родительский контекст; Что делать, если элемент (Flex), который вы ищете, состоит из нескольких родителей, одного брата, а затем нескольких детей? Мы принимаем как должное такие вещи, как jQuery, которые делают это легко, но, очевидно, у нас нет такой роскоши в AS3.

Действует ли что-либо из следующего? Есть ли лучший способ?

  1. Перебирайте родителей и родителей, пока не найдете точку остановки, не найдите брата и сестер, и не перебирайте детей и их детей, пока не найдете свою цель;

  2. Хранить ключевые объекты в глобальном хранилище объектов (sic) и ссылаться на них при необходимости (yech)

  3. Используйте специальные точечные обозначения для достижения цели, включая элементы (такие как скины и их контейнеры - снова yech)

Любые мысли приветствуются.

Edit:

Для пояснения, давайте возьмем пустое приложение Flex 4 AIR. Очевидно, у нас есть WindowedApplication в качестве корня, и давайте добавим двух SkinnableContainer детей с идентификаторами navContainer и mainContainer соответственно. Оба имеют собственные скины. В пределах mainContainer у нас есть еще один SkinnableContainer с вертикальным расположением и идентификатором mainContent, и как один из его дочерних элементов он имеет объект (любой подойдет - искра BorderContainer, может быть) с идентификатором animatedBox, например. В пределах navContainer у нас есть искра Button, у которой слушатель привязан к MouseEvent.CLICK. В рамках этой функции мы хотим получить доступ к animatedBox (nativeWindow.mainContainer.mainContent.animatedBox) и анимировать его, чтобы изменить, скажем, его ширину.

Цель состоит в том, чтобы получить доступ к этому отдаленному DisplayObject (animatedBox) таким образом, чтобы он был как можно более ненавязчивым и эффективным, и в то же время соответствовал стандартам Flex, которыми я явно еще не обладал. :)

Ответы [ 3 ]

1 голос
/ 28 октября 2010

в моей реализации это легко сделать (однако это в чистом AS3):

в экранном объекте, который обрабатывает щелчок:

private function onClick(e:MouseEvent):void{
    Radio.broadcast(new CustomEvent(id, ..params));
}

в animatedBox:

Radio.addListener(id, new Reciever(uid, animate));

private function animate(e:CustomEvent) {
   //needed code and access of CustomEvent props you pass
}

обн:

package lazylib.broadcast 
{
    /**
     * ...
     * @author www0z0k
     */
    public class Reciever 
    {
        private var id: String;
        private var toRun: Function;
        /*@param nm - unique listener id - required
         *@param fn - event handler function - required*/
        public function Reciever(nm:String, fn:Function) 
        {
            id = nm;
            toRun = fn;         
        }

        public function onEvent(e:* = null):String {
            if (e == null) { return id; }
            toRun(e);
            return id;
        }

        public function get ID():String { return id; }

    }

}

и

package lazylib.broadcast
{
    import flash.events.Event;
    import flash.events.EventDispatcher;
    /**
     * ...
     * @author www0z0k
     */
    public final class Radio extends EventDispatcher
    {
        private static var listeners: Object = new Object();
        private static var archive: Array = new Array();
        private static var forSlowpokes: Object = new Object();

        public static function get ForSlowpokes():Object { return forSlowpokes; }

        public static function addListener(type: String , listener: Reciever):Boolean {
            listeners['anchor'] = null;
            if (!listeners[type]) { 
                var o: Object = new Object();
                listeners[type] = o;
            }
            if (!listeners[type][listener.ID]) {
                listeners[type][listener.ID] = listener; 
                return true;
            }else {
                return false;
            }
        }

        public static function broadcast(evt: * , singleUse:Boolean = false):void {
            var type:String = (evt as Event).type;          
            if (listeners[type]) {
                var returned: Array = new Array();
                for (var i: String in listeners[type]) {
                    if(listeners[type][i]){
                        var fnRetVal: String = listeners[type][i].onEvent(evt);
                        returned.push(fnRetVal);
                    }else{
                        //trace("no listener for id = " + i + ' , type = ' + type);
                    }
                }

            }else {
                //trace("nobody's interested in : \"" + type + "\"");
            }
            if (singleUse) {
                forSlowpokes[type] = 'you missed it realtime';
                delete listeners[type];
            }
        }

        public static function clearDeadFuncs(namez:Object):void {
            for (var a:String in namez) {
                if (a != 'anchor') {
                    killListener(a, namez[a]);
                }
            }
        }

        public static function killListener(type: String , id: String):Boolean {
            if (!listeners[type]) { 
                //trace("there are no listeners for event : " + "\"" + type + "\"");
                return false;
            }else {
                if (!listeners[type][id]) {
                    //trace("there is no \"" + id + "\" listener for event : " + "\"" + type + "\"");
                    return false;
                }else {
                    listeners[type][id] = null;
                    //trace("removed listener \"" + id + "\" for event : " + "\"" + type + "\"");
                    var evt2kill: Number = 0;
                    for (var str: String in listeners[type]) {
                        if (listeners[type][str]) {
                            evt2kill++;
                        }
                    }
                    if (evt2kill == 0) {
                        delete listeners[type];
                        //trace("no more listeners for event : " + "\"" + type + "\"");
                        return true;
                    }
                    return true;
                }
            }
        }
    }
}

поставляются как есть;)

0 голосов
/ 12 января 2011

Я задавал себе этот вопрос также много раз.До сих пор не нашли окончательного решения проблемы.Итерация по родителям и родителям - это определенно способ, но к нему следует относиться с осторожностью, потому что отношения могут измениться в вашем приложении во время выполнения.Несколько дней назад я написал простой метод , который позволяет перебирать всех родителей данного объекта.Определенно не элегантное решение, но оно работает до сих пор. SWIZ framework также предлагает хорошие методы для облегчения связи между объектами посредством внедрения кода и передачи событий.Может быть, стоит посмотреть ...

0 голосов
/ 28 октября 2010

Мы принимаем как должное такие вещи, как jQuery, которые делают это легко, но, очевидно, у нас нет такой роскоши в AS3.

ну, есть это: http://tech.nitoyon.com/blog/2008/01/as3query_alpha.html

...