Mam konfigurację zagnieżdżonego widoku, która może nieco zagłębić się w mojej aplikacji. Jest kilka sposobów na inicjalizację, renderowanie i dołączanie widoków podrzędnych, ale zastanawiam się, jaka jest powszechna praktyka.
Oto kilka, o których myślałem:
initialize : function () {
this.subView1 = new Subview({options});
this.subView2 = new Subview({options});
},
render : function () {
this.$el.html(this.template());
this.subView1.setElement('.some-el').render();
this.subView2.setElement('.some-el').render();
}
Zalety: nie musisz martwić się o utrzymanie właściwej kolejności DOM podczas dołączania. Widoki są inicjalizowane wcześnie, więc funkcja renderująca nie ma tak wiele do zrobienia na raz.
Wady: jesteś zmuszony do ponownego delegowania wydarzeń (), co może być kosztowne? Funkcja renderowania widoku nadrzędnego jest zaśmiecona całym renderowaniem widoku podrzędnego, które musi nastąpić? Nie masz możliwości ustawienia tagName
elementów, więc szablon musi utrzymywać poprawne nazwy tagów.
Inny sposób:
initialize : function () {
},
render : function () {
this.$el.empty();
this.subView1 = new Subview({options});
this.subView2 = new Subview({options});
this.$el.append(this.subView1.render().el, this.subView2.render().el);
}
Zalety: nie musisz ponownie delegować wydarzeń. Nie potrzebujesz szablonu, który zawiera tylko puste symbole zastępcze, a Twoje tagName są ponownie definiowane przez widok.
Wady: Musisz teraz upewnić się, że dodałeś rzeczy we właściwej kolejności. Renderowanie widoku nadrzędnego jest nadal zaśmiecone przez renderowanie widoku podrzędnego.
W przypadku onRender
wydarzenia:
initialize : function () {
this.on('render', this.onRender);
this.subView1 = new Subview({options});
this.subView2 = new Subview({options});
},
render : function () {
this.$el.html(this.template);
//other stuff
return this.trigger('render');
},
onRender : function () {
this.subView1.setElement('.some-el').render();
this.subView2.setElement('.some-el').render();
}
Zalety: logika widoku podrzędnego jest teraz oddzielona od metody widoku render()
.
W przypadku onRender
wydarzenia:
initialize : function () {
this.on('render', this.onRender);
},
render : function () {
this.$el.html(this.template);
//other stuff
return this.trigger('render');
},
onRender : function () {
this.subView1 = new Subview();
this.subView2 = new Subview();
this.subView1.setElement('.some-el').render();
this.subView2.setElement('.some-el').render();
}
W pewnym sensie wymieszałem i dopasowałem kilka różnych praktyk we wszystkich tych przykładach (przepraszam za to), ale jakie są te, które chciałbyś zachować lub dodać? a czego byś nie zrobił?
Podsumowanie praktyk:
- Utworzyć instancję podglądów podrzędnych w
initialize
lub wrender
? - Wykonać całą logikę renderowania widoku podrzędnego w
render
lub wonRender
? - Użyj
setElement
lubappend/appendTo
?
źródło
close
metodę i narzędzie,onClose
które czyści dzieci, ale jestem po prostu ciekawy, jak je utworzyć i renderować.delete
w JS to nie to samo, codelete
z C ++. Jeśli o mnie chodzi, jest to bardzo słabo nazwane słowo kluczowe.Odpowiedzi:
Ogólnie widziałem / stosowałem kilka różnych rozwiązań:
Rozwiązanie 1
Jest to podobne do twojego pierwszego przykładu, z kilkoma zmianami:
render()
nazywa się PO umieszczeniu elementu widoku wewnętrznego w DOM, co jest pomocne, jeślirender()
metoda Twojego widoku wewnętrznego polega na umieszczeniu / zmianie rozmiaru na stronie w oparciu o pozycję / rozmiar innych elementów (co jest częstym przypadkiem użycia, z mojego doświadczenia)Rozwiązanie 2
Rozwiązanie 2 może wyglądać na czystsze, ale z mojego doświadczenia wynika, że spowodowało to dziwne rzeczy i miało negatywny wpływ na wydajność.
Generalnie używam rozwiązania 1 z kilku powodów:
render()
metodzie już jestem w DOMPamiętaj, że jeśli inicjalizujesz a przy
new View()
każdymrender()
wywołaniu, inicjalizacja idelegateEvents()
tak zadzwoni . Więc to niekoniecznie musi być „oszustwem”, jak to wyraziłeś.źródło
Jest to odwieczny problem z Backbone iz mojego doświadczenia wynika, że nie ma satysfakcjonującej odpowiedzi na to pytanie. Podzielam twoją frustrację, zwłaszcza, że pomimo tego, jak powszechny jest ten przypadek użycia, jest tak mało wskazówek. To powiedziawszy, zwykle idę z czymś podobnym do twojego drugiego przykładu.
Przede wszystkim odrzuciłbym z ręki wszystko, co wymaga ponownego delegowania wydarzeń. Model widoku sterowanego zdarzeniami w Backbone jest jednym z jego najważniejszych elementów, a utrata tej funkcjonalności tylko dlatego, że aplikacja jest nietrywialna, pozostawiłaby zły smak w ustach każdego programisty. Więc zera numer jeden.
Jeśli chodzi o twój trzeci przykład, myślę, że to tylko koniec z konwencjonalną praktyką renderowania i nie dodaje zbyt wiele znaczenia. Być może, jeśli wykonujesz rzeczywiste wyzwalanie zdarzenia (tj. Nie jest to "
onRender
" wymyślone zdarzenie), warto byłoby po prostu powiązać te zdarzenia zerender
sobą. Jeśli znajdzieszrender
się nieporęczny i złożony, masz zbyt mało podglądów podrzędnych.Wróćmy do drugiego przykładu, który jest prawdopodobnie mniejszym z trzech rodzajów zła. Oto przykładowy kod pobrany z Recipes With Backbone , znajdujący się na stronie 42 mojego wydania PDF:
Jest to tylko nieco bardziej wyrafinowana konfiguracja niż twój drugi przykład: określają zestaw funkcji
addAll
iaddOne
wykonują brudną robotę. Myślę, że to podejście jest wykonalne (iz pewnością go stosuję); ale nadal pozostawia dziwny posmak. (Wybacz wszystkie te metafory językowe).Do twojego punktu dołączania we właściwej kolejności: jeśli dołączasz ściśle, to pewne, to jest ograniczenie. Ale upewnij się, że rozważasz wszystkie możliwe schematy szablonów. Być może faktycznie chciałbyś mieć element zastępczy (np. Pusty
div
lubul
), który możesz następniereplaceWith
dodać do nowego elementu (DOM), który zawiera odpowiednie podglądy. Dołączanie nie jest jedynym rozwiązaniem iz pewnością możesz obejść problem z zamówieniem, jeśli tak bardzo ci na tym zależy, ale wyobrażam sobie, że masz problem z projektem, jeśli cię to potyka. Pamiętaj, podglądy mogą mieć podglądy i powinny, jeśli jest to stosowne. W ten sposób masz raczej drzewiastą strukturę, co jest całkiem przyjemne: każdy podwidok dodaje wszystkie swoje podglądy w kolejności, zanim widok nadrzędny doda kolejny i tak dalej.Niestety, rozwiązanie nr 2 jest prawdopodobnie najlepszym, na jakie możesz liczyć w przypadku korzystania z gotowego do użycia Backbone. Jeśli jesteś zainteresowany sprawdzeniem bibliotek innych firm, jedną z nich zajrzałem (ale nie miałem jeszcze czasu na zabawę) jest Backbone.LayoutManager , który wydaje się mieć zdrowszą metodę dodawania podglądów podrzędnych. Jednak nawet oni mieli ostatnio debaty na podobne tematy.
źródło
model.bind('remove', view.remove);
- czy nie powinieneś tego po prostu zrobić w funkcji inicjalizacji spotkania, aby je oddzielić?Zaskoczony, że nie zostało to jeszcze wspomniane, ale poważnie rozważałbym użycie Marionette .
To wymusza nieco więcej strukturę aplikacji kręgosłup, w tym szczególne widzenia typów (
ListView
,ItemView
,Region
iLayout
), dodając odpowiednieController
S i wiele więcej.Oto projekt na Github i świetny przewodnik autorstwa Addy Osmani w książce Backbone Fundamentals, na początek.
źródło
Mam, jak sądzę, dość kompleksowe rozwiązanie tego problemu. Umożliwia zmianę modelu w kolekcji i ponowne renderowanie tylko jego widoku (zamiast całej kolekcji). Obsługuje również usuwanie widoków zombie za pomocą metod close ().
Stosowanie:
źródło
Sprawdź ten zestaw do tworzenia i renderowania podglądów podrzędnych:
https://github.com/rotundasoftware/backbone.subviews
Jest to minimalistyczne rozwiązanie, które rozwiązuje wiele kwestii omawianych w tym wątku, w tym kolejność renderowania, brak konieczności ponownego delegowania zdarzeń itp. Zwróć uwagę, że przypadek widoku kolekcji (gdzie każdy model w kolekcji jest reprezentowany przez jeden subview) to inny temat. Najlepszym znanym mi rozwiązaniem ogólnym w tym przypadku jest CollectionView w Marionette .
źródło
Nie podoba mi się żadne z powyższych rozwiązań. Wolę tę konfigurację niż każdy widok, który musi ręcznie wykonywać pracę w metodzie renderowania.
views
może być funkcją lub obiektem zwracającym obiekt definicji widoku.remove
wywoływana jest funkcja rodzica,.remove
należy wywołać zagnieżdżone elementy podrzędne od najniższego rzędu w górę (aż do widoków podrzędnych)Oto przykład:
źródło
Backbone został celowo zbudowany tak, aby nie było „powszechnej” praktyki w tej i wielu innych kwestiach. Ma to być jak najbardziej nieopinowane. Teoretycznie nie musisz nawet używać szablonów z Backbone. Możesz użyć javascript / jquery w
render
funkcji widoku, aby ręcznie zmienić wszystkie dane w widoku. Aby uczynić to bardziej ekstremalnym, nie potrzebujesz nawet jednej konkretnejrender
funkcji. Możesz mieć funkcję o nazwie,renderFirstName
która aktualizuje imię w domenie irenderLastName
aktualizuje nazwisko w dom. Gdybyś zastosował takie podejście, byłoby znacznie lepsze pod względem wydajności i nigdy nie musiałbyś ponownie ręcznie delegować wydarzeń. Kod miałby również sens dla kogoś, kto go czytał (chociaż byłby to dłuższy / bardziej niechlujny kod).Jednak zwykle nie ma żadnych wad w używaniu szablonów i po prostu niszczeniu i przebudowywaniu całego widoku i jego podglądów podrzędnych przy każdym wywołaniu renderowania, ponieważ pytającemu nawet nie przyszło do głowy, aby zrobić coś innego. Więc to właśnie robi większość ludzi praktycznie w każdej sytuacji, z którą się spotykają. I dlatego uparte frameworki sprawiają, że jest to zachowanie domyślne.
źródło
Możesz także wstawić wyrenderowane podwidoki jako zmienne do głównego szablonu jako zmienne.
najpierw wyrenderuj podglądy i przekonwertuj je na HTML w następujący sposób:
var subview1 = $(subview1.render.el).html(); var subview2 = $(subview2.render.el).html();
(w ten sposób można również dynamicznie łączyć widoki, tak jak
subview1 + subview2
w pętlach), a następnie przekazać je do szablonu głównego, który wygląda tak:... some header stuff ... <%= sub1 %> <%= sub2 %> ... some footer stuff ...
i na koniec wstrzyknij to w ten sposób:
this.$el.html(_.template(MasterTemplate, { sub1: subview1, sub2: subview2 } ));
Odnośnie zdarzeń w widokach podrzędnych: Najprawdopodobniej będą one musiały być połączone w nadrzędnym (masterView) z tym podejściem, a nie w widokach podrzędnych.
źródło
Lubię stosować następujące podejście, które również zapewnia prawidłowe usuwanie widoków podrzędnych. Oto przykład z książki Addy Osmani.
źródło
Nie ma potrzeby ponownego delegowania wydarzeń, ponieważ jest to kosztowne. Zobacz poniżej:
źródło