Diskuze: Vyhledávání na webu mezi elementy
V předchozím kvízu, Online test znalostí HTML a CSS, jsme si ověřili nabyté zkušenosti z kurzu.
Neaktivní uživatel:6.4.2016 22:59
Jsou to jen elementy na webu? Jen elementy co jsou v soucasne dobe nactene v DOMu? (zjednodusene receno to, co muzes videt v okne prohlizece?) Pokud ano, vykasli se na phpcko ... tady se vsecka prace bude delat na klientu, pokud mas milion divu na strance, kazdy ma nejaky atribut a ty podle tech atributu chces vyhledavat, pak je JS presne pro tebe.
Jenoduse udelas
<input id="search" type="text">
, v javascriptovem kodu mu nastavis naslouchani na udalost onkeyup
(document.getElementById("search").addEventListener("keyup", function(){});
Uvnitr funkce budes nacitat do stringu obsah inputu v danej moment, pak to chce funkci, ktera vybere vsechny elementy, ktery by mohly bejt ve hre, na to muzes pouzit velice silnej selector document.querySelectorAll (https://developer.mozilla.org/…ySelectorAll) vyhleda ti po spravnem specifikovani elementy s danou id, s danou classou, s kombinaci, daneho tagname, daneho atributu, proste je to jako svicarskej nuz, co budes s danyma elementama delat je na tobe, muzes skryt vsechny, krome tehle, muzes tyhle posunout nahoru, muzes je obarvit na duhovo, to je jedno ... dobry je, ze i kdyz si uzivatel umaze kousek stringu, tak backspace taky aktivuje keyup ...
pozor si dej na tohle, pokud to budes delat takhle, tak se ti muze stat, ze ti v jeden moment pri rychlejsim pripisovani pozadavku a pomalem vyhledavani nastane situace, kdy bys pri neustalem aktualizovani DOMu par sekund jen blikal zobrazit/schovat/zobrazit/schovat, protoze javascript bezi synchronne nemel by starsi vypocet dobehnout pozdeji, nez mladsi, ale dobehnou velmi kratce za sebou tak jak pisu velmi rychle slovo a to znamena, ze pri slove dlouhem deset pismen desetkrat zbytecne manipulujes s DOMem, nebo zbytecne desetkrat menis display velkemu mnozstvi prvku, to neni zadarmo.
Takze jak se tomu vyvarovat, no javascript nenabizi mnoho hezkych reseni, jednim z nich je mit globalni promennou, na kterou uvidi vsechny tyhle funkce, ktere se budou provadet na stisk tlacitka v inputu a ted pozor, nemuzes zastavit provadeni funkce v atomickem prikazu, ber to tak, ze proste nejde rict interuptni se zrovna v okamziku kdy javascript louska treba ten tvuj DOM a hleda spravne elementy, ALE co jde a je to docela elegantni -> predtim, nez doopravdy zacnes hybat s DOMem (zvyraznovat vyhledany vysledky, posouvat je, skryvat ostatni, atd...) se ujistis, ze tohle volani, je to posledni, to chce hned na zacatku funkce do lokalni promenne ulozit timeStamp, pak bude globalni timeStamp, do kteryho na zacatku volani (hned na to zvednuti prstu) zapises taky, nez tedy (zase se posuneme na konec tve funkce) provedes neco s tema elementama, ujistis se, ze ten lokalni timeStamp souhlasi s tim globalnim, pokud souhlasi, vis ze tohle volani/provadeni je to aktualni/posledni chtene .. pokud nesouhlasi, znamena to, ze byla zavolana instance teto funkce znovu, logicky s jinyma datama, no a ty proste udelas return a nic nezobrazujes, skoda, ze jsi hledal mezi elementama zbytecne, ale to je zivot...
Nekomu by mohl vadit fakt, ze timeStamp (ten hlavni) je zde pristupovan a nebyl funkci pridelen, bohuzel se s tim asi budes muset smirit, nenapada me ted zpusob co by nezneuzival vareable object funkce ...
Doufam, ze jsem to popsal alespon slovne dost detailne, otazka znela dost na popis implementace, kdybys stal o vic kodu a prikladu, pravdepodobne te pozadam o doplneni nejakeho ukazkoveho kodu (co uz mas treba) a jsem ti ochotny k tomu neco dopsat, poradit.
Taky bys mohl pockat az user zmackne enter, ale nekdo je zvyklej klikat na lupu, nekdo enteruje a jak jsem pochopil, ty to chces auto.
Tak, tohle sem nečekal.. To byla opravdu vyčerpávající odpověď Vážím si toho.. A ano asi budu potřebovat trochu více kódu kvůli trochu praktiky. nejsem v JavaScriptu nijak extra zběhlý a tak se to učím spíš za pochodu.
Myšlenku tohohle všeho chápu, jen bych to potřeboval trochu přiblížit v té praxi no. A ano nemělo by se tam klikat na žádné tlačítko ani lupu ani ukončovat enterem, ale tou změnou znaku.
Já sem ještě s kódem moc nezačal, protože sem chtěl vědět jak bude vypadat tohle abych se k tomu nějak přispůsobil, kdyby to bylo nějak složité. Ale asi bych to vzal tak že budu mít na stránce několik divů, který budou mít asi class="box <jmeno>" takže box bude pro stylování všech divů na té stránce a <jméno> tam bude jméno podle kterého bude vyhledávání.
<p><input class="vstup" /></p>
<div class="box Pepa">IMG</div>
<div class="box Jroslav"IMG</div>
<div class="box Vladimír">IMG</div>
<div class="box Ludmila">IMG</div>
<div class="box Karolína">IMG</div>
<div class="box Karel">IMG</div>
<div class="box Jiří">IMG</div>
Zkrácený kód. Nahoře je vstupní polu do kterého se bude psát co se bude vyhledávat a bude se vyhledávat mezi divy pod tím.. Je to jen teoretické, takže názvy atp bych neřešil tak moc je to jen pro ukázku. Stylování tu taky neřeším. Po vyhledání bych asi nechal jenom vyhledané a ostatní bych schoval
Dále nevím jak to bude fungovat a hledat. Ale bylo by dobré, kdyby to nehledalo jenom celé názvy, ale kdybych do vyhledávacího pole napsal například "m" tak aby mi vyskočil Vladimír a Ludmila atp. Prostě aby to hledalo i to co mají společné.
Neaktivní uživatel:7.4.2016 10:33
Já jsem tam samozřejmě těmi úpravami a přepisováním udělal chybu v té části o zastavování již nepotřebného vyhledávání, ale když počkáš 30 minut až budu ve škole už pro tebe mám připravené správné řešení i s odpovědí na poslední otázky.
Neaktivní uživatel:7.4.2016 12:28
Takze, prvni co bych udelal, rozdelil oznacovani elementu na tri mnoziny, pomoci ID, pomoci CLASS, pomoci data-* ... zasadni je rychlost a citelnost kodu.
Tvemu input elementu bych dal id="search" a tridu bych mu nedaval,
tvym divum bych nechal class="box" ale to je jedina trida co by mely mit,
jejich jmeno, tag, stitek, cosi, to je informace, ktera nepatri do class, je to
ve skutecnosti informace, kterou by mel nest atribut data- ... treba
data-tag="Pepa", proc? Ve skutecnosti se podle ID hleda jedinecnej kontent na
strance, je to rychly, v kodu prehledny a nejde to nemit rad, classou oznacenych
elementu je hodne, obvykle se pomoci tridy styluje, obvykle se podle tridy v JS
vybira seznam (mnozina) elementu vyhovujicich nejakemu kriteriu, ovsem co ta
pridavna informace o tom poli, pokud je box elementem jednoho zaznamu, tak kazdy
zaznam musi byt podle neceho vyhledan, no a tahle pridana informace patri do
atributu data*, atributy se v javascriptu ctou velmi snadno, neni duvod to
nepouzit, tvoje html pak bude vypadat mnohem cistejsi. No proste jdi do
toho.
A pak resime problem s zobrazenim pouze vyhovujicich, ve skutecnosti jde o pravy opak zejo, ty se snazis najit ty ktery nevyhovoujou a schovat je, bohuzel myslim, ze querySelectorAll neumi regularni vyrazy, ale to ve vysledku nevadi, poresime si to sami, querySelectorAll ti poslouzi na ziskani seznamu vsech box divu, pak pojedes forem jeden po druhem a budes zjistovat jestli ten konknretni element ma v atributu data-tag ukryty substring pomoci metody indexOf (http://www.w3schools.com/…_indexof.asp) pokud tahle metoda vrati zaporne cislo hledany vyraz se tam nenechazi, pak element skryjeme, pokud se tam nachazi pak element nechame byt.
A ted opraveni me predchozi chyby, pokud chces stornovat ulohu po pripsani dalsiho pismena, musis pouzit figl a setTimeout(), jednoduse to udelas tak, ze na udalost stisku klavesy uvnitr inputu zachytis cas, zapises si ho globalne a pak zavolas s pul vterinovym zpozdenim dalsi funkci, predas ji obsah inputu, predas ji cas ve ktery byla vyvolana, predas ji odkaz na globalni timeStamp (jen kvuli elegantnimu kodu) a zasadni je, ze se provede z pulvterinovym zpozdenim, za tu dobu totiz prumerny clovek napise dalsi pismeno pokud chce, dojde k prepsani globalniho casoveho razitka (timeStamp) no a az se provede jiz stara a nechtena vyhledavaci procedura, prvni co po spusteni/probuzeni vykona je porovnani globalniho timestampu a sveho lokalne obdrzeneho v parametrech, pokud nesouhlasi return a nic dal se neresi, takhle se probublas az k te jedine vyhledavaci procedure, ktera nebude nicim nahrazena a ta se provede.
Prilozim ti ukazkovy torzo kodu:
window.onload = function () {
var searchStamp = {time: new Date()};
document.getElementById("search").addEventListener("keyup", function (event) {
if ((!event.ctrlKey) && (event.keyCode > 45 && event.keyCode < 91) || event.keyCode === 8) {
console.log("reakce");
// jen pokud se pripsalo pismeno, nebo bylo nejake smazano, nekdo taky mohl jen stisknout spiku
// taky to reaguje na delete a backspace
// a ignoruje vstup, pokud byla stisknuta ctrl klavesa napriklad pro oznac vse
var localTimeStamp = new Date();
localTimeStamp = localTimeStamp + localTimeStamp.getMilliseconds(); // jde nam vazne o velmi presne casove rozlisovani
searchStamp.time = localTimeStamp; // otiskneme do globalniho casu
setTimeout(function (localTime, globalTime, slovo) {
if (localTime != globalTime.time) {
return;
}
var listElem = document.getElementsByClassName("box"); // ziskam seznam vsech elementu
for (var i = 0; i < listElem.length; i++) {
if (listElem[i].getAttribute("data-tag").indexOf(slovo) < 0) {
// v atributu data-tag nebyl nalezen string, ktery je v soucasnosti v inputu
listElem[i].style.display = "none";
} else {
listElem[i].style.display = "block";
// jen pro pripad, ze by byl skryt predchozim vyhledavanim
}
}
}, 500, localTimeStamp, searchStamp, document.getElementById("search").value); // predavani dalsich parametru nefunguje v IE 9 a nizsich
}
})
};
Doufam, ze ted uz bez chyb, v podstate je to zakladni reseni tveho problemu pamatujici i na zakladni klavesove zkratky pro oznaceni celeho textu, pripadne moznosti, ze user se rozhodne pouzit ctrl find a podobne, kdyz bude uvnitr tveho formu.
Kdyztak si napis o dalsi pdorobnosti.
Verquido:8.4.2016 18:32
A také když ty diy mizí tak je to moc rychlý, chtělo by to tam nějaký přechod ale nevím kam to vrazit
Neaktivní uživatel:8.4.2016 23:43
Ohledne casovace, v zasade jde o tohle, kdyz ta akce bude nasledovat na
udalost stisknuti klavesy (presneji zvednuti tisknute klavesy - protoze je to
onkeyup), tak se to neprodlene po ni provede, vis co to znamena?
Ze pokud tam bude dlouhej task a ja do inputu napisu pet pismen, tak pro kazdy
jedno dalsi pismeno se ten dlouhej task provede znova to prece nechces!
Nestojis o to neustale prohledave, elementy a hejbat s DOMem, nebo stylama na
kazdou nerelevantni zmenu, to je spatne, ale nejde to zastavit, javascript je
synchronni (az na vyjimky a triky), takze jakmile se ten proces rozbehne, tak ho
nikdo nezastavi, nepredbehne, nevkroci mu do cesty, aby mohl prehodit
vyhybku...proste NE ... od toho je tu ten malej trik.
V zasade rikam: Na udalost stisknuti klavesy reaguj neprodlene tak, ze
zaznamenas cas stisku a ulozis ho do globalniho objektu, ktery je na to
zkonstruovany a pote naplanujes ulohu se zpozdenim pul vteriny.
K cemu mi to je dobry? Za tu pul vterinu stihne prumernej clovek napsat dalsi
pismeno, pokud chce, opet se neprodlene provede zaznam casu (aha....provede se,
protoze mu v provadeni nic nebrani, kdybych ale rozbehl vyhledavani hned, muselo
by dalsi pismeno cekat nez se funkce, prirazena udalosti keyup zacne provadet),
tedy opakuji, provede se zaznam casu a v globalnim timeStampu se cas zmeni, kdyz
uz user nic nepripise, za maly okamzik se probudi casovac od prvniho pismenka,
prvni co udela je, ze se koukne v jaky cas bylo vlozeno pismenko, jez bylo jeho
spousti, (funkce dostala ten cas jako argument) porovna ten cas s globalnim
poslednim stiskem tlacitka (taky argument) a pokud se lisi (v tomhle pripade
ano) rekne si: "skoda, user uz mezitim napsal dalsi pismeno, takze tenhle muj
pozadavek je uz zbytecnej", hodi return a konec, za maly okamzik se spusti druhy
casovac...zkontroluje casy, jsou shodne, provede hledani, provede zobrazeni a
skryti elementu no a parada mas cos chtel...
ohledne nejakyho fadeout/fadein efektu, najdi si co ti vyhovuje, jQuery ma fadeIn fadeOut funkce, budes je vkladat jednoduse tam, kde menis vlastnost display elementu, nezapomen, ze display bud zakomentujes uplne, nebo v zavislosti na tom jak funguje ta konkretni implementace fade funkci, udelas nejdriv fade a pak se ujistis zmenou displaye, ze je element kompletne srkryt, nebo zobrazen. Samotnej javascript nenabizi jendoduchou radkovou variantu postupneho zmizeni, ci postupneho prolnuti.
No doufam, ze mas co potrebujes, samozrejme uloha nabizi prostor pro nejaky mikrooptimalizace, napriklad, co je lepsi rict jiz skrytemu elementu at se skryje (opetovne mu nastavit display na none i kdyz tak uz byl) nebo se ifem ujistit ze je vlastnost display rovna none a pouze paklize neni, ji prepsat. To necham na tobe, posune te to blize k spravnemu stylu psani webappek.
+20 Zkušeností
+2,50 Kč
Verquido:17.4.2016 12:48
Ahoj, ještě dodatečně mě teď napadlo že to řeší i velká a malá písmena.. Jak by šlo udělat aby to nebralo v ohledu jaký to jsou?
Neaktivní uživatel:17.4.2016 17:56
pouzijes na atribut .toUpperCase() a do indexOf() to pridas taky - abys uppercasoval i ten vyhledavanej vyraz ... nebo muzes pozuti opak, ale je to jedno, jde o to ze si vsechny stringy prevedes na velky pismena a vsechny vyhledavany vyrazy take ... no a pak je to jasny .. je?
Verquido:17.4.2016 19:37
Super, díky Já to dával jenom k tomu indexOf() .. proto mi to nešlo
Zobrazeno 14 zpráv z 14.