Autor Zpráva
Suta
Profil
Uvedu jeden z možných příkladů. Mám kontextové menu, které vkládám do stránky po kliknutí pravým tlačítkem. Kliknutím levým tlačítkem myši je toto menu skryto / odstraněno.

Pokud by menu bylo neměnné, pak není problém jej jednou vytvořit a jeho vložení do stránky realizovat pomocí display (none, block), visibility či vyjmutí / vložení pomocí removeChild / appendChild.

Problém je v tom, že menu je vytvářeno dynamicky v závislosti na tom, kde bylo vyvoláno. Navíc má další submenu, jehož položky mohou být opět pokaždé odlišné.

Otázky zní:

1. Zatěžuje neustálé dynamické vytváření vždy nových elementů (potřebné pro vytvoření aktuálně platné nabídky) paměť prohlížeče?

2. Stačí kořenový element menu (resp. odkaz na něj uložený javascriptem) odebrat ze stránky pomocí removeChild? Nebo je třeba jej poté kvůli paměti nastavit na null? (jen podotknu, že na menu nepřipojuji žádné události, ty zpracovávám pomocí delegování událostí na hlavní dokument).

Díky za připomínky a rady.
Witiko
Profil
Suta:
Stačí kořenový element menu (resp. odkaz na něj uložený javascriptem) odebrat ze stránky pomocí removeChild? Nebo je třeba jej poté kvůli paměti nastavit na null?
To ale ani udělat nemůžeš. V proměnné máš vždy jen referenci na objekt, null přiřadíš do proměnné, ne objektu. Ten bude sám vymazán garbage collectorem, jakmile na něj neexistuje platný odkaz. Do té doby budou odkazy směřovat na mrtvý DOM element, který je mimo tok dokumentu.

Zatěžuje neustálé dynamické vytváření vždy nových elementů (potřebné pro vytvoření aktuálně platné nabídky) paměť prohlížeče
Pakliže nejsou nikde uchovávány reference na již neplatné elementy a prohlížeč neleakuje (starší Explorery při zacyklených referencích), pak ne.
Suta
Profil
Witiko:
V proměnné máš vždy jen referenci na objekt, null přiřadíš do proměnné, ne objektu.
Samozřejmě, nicméně podstatné je to, že mám-li element (dobře, odkaz na něj) uložený v proměnné (či vlastnosti objektu), pak po jeho vyjmutí ze stránky pomocí removeChild() zůstane odkaz na element stále v této proměnné (resp. vlastnosti objektu). Proto mám zato, že je bezpečné vždy tuto provázanost zrušil nastavením na prázdný objekt (null).
_es
Profil
Suta:
tuto provázanost zrušil nastavením na prázdný objekt (null).
Alebo nastavením na hocičo iné, podstatné je to, aby na ten objekt neexistoval odkaz.
Môžeš aj používať stále jeden, či viaceré, tie isté, objekty, ktorým nastavíš iný vzhľad, či ch vyjmeš, alebo vložíš do dokumentu - namiesto vytvárania nových a rušenia „starých“ objektov.
Suta
Profil
_es:
To je zajímavá myšlenka. Zkusil jsem na jejím základě postavit objekt, který uchovává všechny možné položky kontextového menu (a je kdykoliv v průběhu možno zaregistrovat další). Každá položka má svůj html kód, takže je vytvořena pouze jednou. Je-li třeba změnit její vzhled, stačí změnit její styl (či lépe styl pro celé menu, detaily nyní neřešme, ani to, že pro položku menu je namísto tagu li použit div...).

<script type="text/javascript">
contextMenu = {};
contextMenu.itemList = {};
contextMenu.registerItem = function() {
    var arg = arguments[0];
    contextMenu.itemList[arg.name] = {
        className:  arg.className,
        text:       arg.text,
        html:       function() {
            var div;
            div = document.createElement("div");
            $(div).attr("itemName",arg.name);
            $(div).addClass("item"); //defaultní styl pro položku
            if(arg.className) $(div).addClass(arg.className); //volitelný styl pro položku (ikona)

            return div;
        }()
    }
}
</script>


Nyní můžu položku zaregistrovat do systému např. takto:

contextMenu.registerItem({
        name:       "new",
        className:  "new",
        text:       "Nový"
    });
contextMenu.registerItem({
        name:       "edit",
        className:  "edit",
        text:       "Upravit"
    });
    


Konkrétní položka (její html kód) je nyní uložena ve vlastnosti contextMenu.itemList["new"].html. Při vytváření dynamického kontextového menu ji nyní stačí vložit do hlavního rodiče kontextového menu.

Je na tomto způsobu něco zásadně špatně?
_es
Profil
Suta:
Ja som to myslel tak, že by sa len upravoval element DOM. Teda zobrazil, skryl, vyňal alebo vložil do dokumentu, upravil jeho vzhľad, pozícia, atď. Teda by nebolo treba ten element vytvárať, len by sa upravoval. Nejaký objektový obal, ešte v kombinácii s nejakým frameworkom, je nepodstatný.
Suta
Profil
_es:
Chápu. Zeptám se jinak.

Mám-li element vytvořený javascriptem uložený v objektu, vložím jej do dokumentu a následně nastavím vlastnost innerHTML dokumentu na prázdný řetězec. Následně element uložený v objektu opětovně vložím do dokumentu.

K čemu přesně dojde? Může to mít nějaká negativa?

var obj {};
      obj.element = document.createElement("div");
      document.body.appendChild(obj.element);
      document.body.innerHTML = "";
      document.body.appendChild(obj.element);
_es
Profil
Suta:
Mám-li element vytvořený javascriptem
Ten element máš v obj.element, nie v obj.
Nastavením innerHTML elementu body zrušíš elementy v body, no nie element v obj.element, lebo naň máš odkaz. No neviem, ako by sa s opätovným vložením takéhoto elementu, u ktorého nie je isté, čo by sa s ním po takejto úprave jeho nadradeného elementu malo stať, vysporiadali rôzne prehliadače.
Suta
Profil
_es:
...„zrušíš elementy v body, no nie element v obj.element“...
Přesně tak. Mně jde o to, mít vytvořeno třeba 100 různých položek kontextového menu, které se vytvoří pouze jednou. A poté vkládám vždy pouze ty, které potřebuji. Tedy zmáčkne-li uživatel pravé tlačitko myši nad dokumentem, vloží se do kontextové nabídky určité položky, po skrytí se z nabídky vyjmou (removeChild). Po stisknutí pravého tlačítka nad něčím jiným se vloží jiné položky atd..

Snad je tento postup v pořádku. Nevím o lepším.
_es
Profil
Suta:
Snad je tento postup v pořádku
Pokiaľ doňho nezahrnieš nastavenie vlastnosti innerHTML nejakého elementu obsahujúce iné elementy, na ktoré existuje odkaz - ako v [#7], čo by snáď teoreticky mohol byť problém.
Suta
Profil
Edit po 4 měsících - pouze poznámka k innerHTML == "" a následnému pokusu vložit takto "odstraněný" element zpět pomocí appendChild (či jinak).

_es:
čo by snáď teoreticky mohol byť problém.
Právě dnes jsem narazil a vzalo mi to tři hodiny hledání, takže ne jen teoreticky, ale skutečně i prakticky.

Příklad:
var parentElement = document.getElementById("parent");
var child = parentElement.lastChild;
parentElement.innerHTML = "";
parentElement.appendChild(child); // nejede v IE - v konzoli nehlásí žádnou chybu, obsah elementu child se však ve stránce neobjeví (testováno v IE8)
Chamurappi
Profil
Reaguji na Sutu:
Při mazání innerHTML se mažou i obsahy potomků, pokud si dobře vzpomínám. Takže ten element se přidává, ale má také prázdné innerHTML.

Vaše odpověď

Mohlo by se hodit

Neumíte-li správně určit příčinu chyby, vkládejte odkazy na živé ukázky.
Užíváte-li nějakou cizí knihovnu, ukažte odpovídajícím, kde jste ji vzali.

Užitečné odkazy:

Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0