AS3 / Flex 4: наиболее практичный способ поиска вложенных дочерних элементов

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

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

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

Правильно ли что-либо из следующего? Есть ли способ лучше?

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

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

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

Любые мысли будут оценены.

Изменить:

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

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


person mway    schedule 28.10.2010    source источник
comment
Итак, вы ищете лучший способ просто передавать события объектам, находящимся далеко в списке отображения, или вам нужно создать своего рода карту списка отображения?   -  person www0z0k    schedule 28.10.2010
comment
почему вы на самом деле хотите это сделать? Помните, что AS3 - это больше объектно-ориентированный подход, чем JS, поэтому почти наверняка существует лучший объектно-ориентированный способ решения вашей проблемы, чем один из трех перечисленных методов.   -  person Gregor Kiddie    schedule 28.10.2010
comment
я не могу понять ваш вопрос. Однако создайте массив, в котором будут храниться ссылки на все объекты, используемые в swf, и этот массив будет многомерным. например, у stage есть три дочерних элемента, а у дочернего элемента 2 есть еще 3 дочерних элемента, тогда вы можете использовать removechild (GlobalRef [1] [0]), чтобы удалить дочерний элемент 1 из второго дочернего элемента stage. означает вложение ссылки по мере вложения объектов.   -  person Muhammad Irfan    schedule 28.10.2010
comment
Если вопрос в том, как прослушивать события от объектов, находящихся далеко в списке отображения, у меня есть решение   -  person www0z0k    schedule 28.10.2010
comment
@ www0z0k: Я не собираюсь специально проводить мероприятия; Я хочу получить к ним доступ, чтобы я мог либо привязать прослушиватели событий, либо, что более важно, изменить их свойства.   -  person mway    schedule 28.10.2010
comment
@ Грегор Кидди: О, определенно. Мне очень комфортно с AS3, но мне не кажется, что Flex имеет такую ​​же простоту обхода иерархической структуры отображения, как обычный Flash; было бы проще, если бы я использовал атрибут name вместо id?   -  person mway    schedule 28.10.2010
comment
Обычно потому, что Flex работает по более современным стандартам, чем Flash. Какой вариант использования вы на самом деле пытаетесь решить, чтобы мы могли атаковать его более гибким способом.   -  person Gregor Kiddie    schedule 28.10.2010
comment
@mway: я использую собственный класс Radio со статическими функциями addListener, killListener и broadcast, поэтому мне не нужно заботиться об иерархии списка отображения в моей модели событий. это поможет вам?   -  person www0z0k    schedule 28.10.2010
comment
@ www0z0k: Хм ... Я тоже написал класс управления событиями, который хранит обратные вызовы по имени и сопоставляет их с теми элементами, к которым они привязаны (что на самом деле не нужно, его единственная реальная цель - иметь интерфейс для привязки их). Хотя я был бы рад взглянуть.   -  person mway    schedule 28.10.2010
comment
@mway: обновил свой ответ   -  person www0z0k    schedule 29.10.2010


Ответы (3)


в моей реализации это легко сделать (правда, в чистом 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
}

UPD:

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

доставлено как есть;)

person www0z0k    schedule 28.10.2010
comment
В итоге я понял, что все элементы с идентификаторами доступны через точечную нотацию из ссылки в главном окне; но это очень удобно, поэтому я приму ваш ответ на предложения. :) Спасибо! - person mway; 01.11.2010

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

ну вот это: http://tech.nitoyon.com/blog/2008/01/as3query_alpha.html

person Daniel    schedule 28.10.2010
comment
Выглядит интересно. Однако, не рассматривая это слишком серьезно, я задаюсь вопросом о производительности и о том, сколько накладных расходов возникнет при использовании более крупного приложения. - person mway; 29.10.2010

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

person Chris    schedule 12.01.2011