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 с вертикално оформление и ID mainContent, и като едно от неговите деца, той има обект (всеки ще свърши работа - искра BorderContainer, може би) с ID 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 е повече OO отколкото JS, така че почти сигурно има по-добър OO начин за подход към вашия проблем от един от 3-те изброени метода.   -  person Gregor Kiddie    schedule 28.10.2010
comment
не мога да разбера въпроса ти. Направете обаче масив, който ще съхранява препратки към всички обекти, използвани в swf, и този масив ще бъде многоизмерен. например етапът има три деца и дете 2 има още 3 деца, тогава можете да използвате removechild(GlobalRef[1][0]), за да премахнете детето 1 от етап 2-ро дете. означава влагане на препратката, тъй като обектите са вложени.   -  person Muhammad Irfan    schedule 28.10.2010
comment
ако въпросът е как да слушам събития от обекти, далеч в списъка за показване, имам решението   -  person www0z0k    schedule 28.10.2010
comment
@www0z0k: Не искам да предавам специално събития; Търся достъп до тях, за да мога или да обвържа слушатели на събития, или, което е по-важно, да променя свойствата им.   -  person mway    schedule 28.10.2010
comment
@Gregor Kiddie: О, определено. Много ми е удобно с 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
}

актуализиран:

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 също предлага добри методи за улесняване на комуникацията между обекти чрез инжектиране на код и посредничество на събития. Може би си струва да се погледне...

person Chris    schedule 12.01.2011