Autor Zpráva
Trax
Profil
Ahoj přátelé,

touto cestou bych vás rád poprosil o pomoc. :)

Snažím se o dynamické načítání stránek z databáze. A jelikož si s JavaScriptem úplně nerozumím, potřeboval bych vaše rady a zkušenosti.
Mám stránky kde se mi v PHP vypisují z databáze data do divu .stranka (za pomocí $_GET). Nutno však dodat že používám RewriteRule, tudíž podoba URL adresy vypadá jako www.domena.cz/stranka
A já potřebuji po kliknutí na odkaz v menu změnit obsah stránky, URL adresu a pozadí stránky (cestu k pozadí mám rovněž uloženou v DB). - to vše bez znovu načtení stránky (refresh).

Již se mi něco podařilo zbastlit i se změnou pozadí pomocí různých článků na netu. Ale například se mi nezobrazují ty URL adresy a mám tam ještě více nedostatků, které bych chtěl vyřešit. A bojím se, že když začnu, tak u některého problému bych zjistil, že jsem to začal řešit špatnou metodou a proto bych vás poprosil o nějaké rady, zkušenosti a nasměrování.


1. Prvním problémem mám tedy ty URL adresy. Jak zmiňuji výše, chtěl bych aby URL vypadala takto: www.domena.cz/stranka Hlavně z důvodu, aby se na jednotlivé stránky dalo odkazovat. Tedy po zadání příslušné domény, se zobrazila příslušná stránka.
2. Aby se se stránkou měnilo pozadí, které je ovšem úplně v jiném divu.
3. Zpoždění načtení z důvodu animací. Mám již vytvořené animace, které způsobí, že po kliknutí na odkaz stránka i pozadí zajede za okraj obrazovky a přijede nová stránka a nové pozadí (dříve jsem měl každou stránku zvlášť v jiném divu) Ale jelikož se v každém divu animovalo jiné pozadí, stránka se dlouho načítala. To by ovšem mělo odpadnout, pokud budu pro načítání stránky používat jeden soubor a tím pádem i jeden div pro pozadí. (pokud se pletu opravte mě) .... Takže jinak řečeno, potřebuji, aby se stránka aktualizovala dejme tomu po 500ms, tedy ve chvíli, kdy zajede za okraj.
4. Ne všechny stránky jsou stejné (stejně nastylované). Resp. mám 5 rozdílných stránek: úvodní, služby, novinky, reference a kontakt. Každá z nich má jinou koncepci. (toto je jedna z věcí, na kterých jsem strávil skoro půl dne a nepřišel jsem na ni.), potřebuji tedy asi nějakou podmínku, která bude rozlišovat, který soubor se načte. (opět - pokud se mýlím opravte mě)

Záměrně tu nepíši, žádný kód, abych se neodrazil od toho špatného. Ale abych nastínil situaci, tak tady je zjednodušená koncepce stránky.

<div id="pozadí" style="background-image: url(<?php echo($cesta); ?>)"></div> // Zde se mi načítá pozadí

<div id="filtr"></div> // zde mám druhé statické pozadí, které se nemění (jen pro grafický efekt), ale je nutné, aby bylo nad divem #pozadi

<div class="stranka"><php require("sluzby.php"); ?></div> //zde načítám služby

//momentálně to mám tak, že div .stranka mám i pro zbylých čtyř koncepcí stránek tedy:

<div class="stranka"><php require("uvod.php"); ?></div>
<div class="stranka"><php require("novinky.php"); ?></div>
<div class="stranka"><php require("reference.php"); ?></div>
<div class="stranka"><php require("kontakt.php"); ?></div> 

//ovšem myslím si, že by bylo lepší to mít pouze v jednom divu. Jen úplně nevím jak na to a zároveň nevím, zda uvažuji správným směrem.... :)

Proto Vás prosím o rady a poznatky. Předem děkuji.
DarkMeni
Profil
Tak je hlavně potřeba vědět, jestli tam bude dynamický obsah (může se měnit na základě vstupu od návštěvníka) nebo ne?
Trochu mě mate ten filtr, jestli se tím myslí filtrování třeba produktů, tak tam bude dynamický obsah, jestli je to jen něco pro css, tak ne.

To rozhodne jestli bude potřeba AJAX nebo ne.
Takže?
Trax
Profil
DarkMeni:
Filtr je jen grafická záležitost (je to průhledné pozadí s motivem)

Teď jsem zmaten já tím dynamickým obsahem. :-) Jako plánuji, že tam bude kontaktní formulář a login. Pokud tedy myslíte jako vstup tohle.
DarkMeni
Profil
K 1., pro změnu adresy v adresním řádku aniž by to vyvolalo refresh jde použít window.history.pushState("", "", "jina-stranka"); nebo replaceState, prostě něco z window.history...

Já bych to udělal asi tak, že na straně serveru dám na výstup divy se všema stránkama jak to máš teď (je jich asi 5 že? a každá tak 5 - 10kB? to by mělo být v pohodě) s tím, že bych zjistil která se má aktuálně zobrazit (kdyby návštěvníkovi nefungoval javascrit, tak aby pořád měl možnost ty stránky vidět) a té bych přidal ještě class "aktivni", což by přepsalo display:block oproti ostatním divům, které by měly jen class "stranka" a tam by byl display:none. Jak moc mají různou koncepci? Alespoň menu by mohlo být vždy na stejném místě.

index.php
<?php
// ...
$stranky = array("uvod", "novinky", "reference", "kontakt");
$pozadovana = isset($_GET["stranka"]) && in_array($_GET["stranka"], $stranky) ? $_GET["stranka"] : $stranky[0];
foreach($stranky as $stranka)
{
  $aktivni = ($stranka == $pozadovana ? "aktivni" : "");
  echo "<div class=\"stranka $aktivni\" id=\"$stranka\">" . include("$stranka.php") . "</div>"; 
}
// ...
?>

A odkazy v menu
<a href="/novinky" onclick="zobrazStranku('novinky');return false;">Novinky</a>

Javascript
function zobrazStranku(stranka){
  skryjAktualniStranku();
  aktualizujPozadi(stranka);
  // Pripadne nejaka animace
  document.getElementById(stranka).classList.add("aktivni");
  window.history.pushState("", "", "/" + stranka);
)

function skryjAktualniStranku()
{
  // Pripadne nejaka animace...
  document.getElementsByClassName("aktivni")[0].classList.remove("aktivni");
}

function aktualizujPozadi(stranka)
{
  // Nejjednodušší by bylo, kdyby byly ve stejné složce, jmenovali se podle stránky, ke které patří, a měly stejný formát, jinak by se to muselo udělat přes asociativní pole (v javasriptu by to byl objekt)
  document.getElementById("pozadi").style.backgroundImage = "url('obrazky/pozadi/" + stranka + ".jpg')";
}
(nezkoušel jsem to, takže kdo ví jestli to bude fungovat, ale jen jako nástin, jak by se to dalo udělat)
Jak máš udělané ty animace? Čistě přes javascript, jquery nebo css?

Jo a ty styly
.stranka { /* styly pro div s obsahem stranky a pak: */ display:none; }
.stranka.aktivni { display:block; }
Trax
Profil
Děkuji mnohokrát, potřeboval jsem se odrazit. :) Většinu jsem dokázal nějakým způsobem udělat.

Na bod 3 jsem ale zatím ještě nepřišel.

Zkoušel jsem to dvěma způsoby:

A)
var Bg = $(this).attr('href');
$("#pozadi").css('background-image', 'url(/TraxartSystem/galerie/bg_' + Bg + '.jpg)');

B)
var Bg = $(this).attr('href');
$('#pozadi').load(Bg+' #pozadi'),

function(output) { $('#pozadi').html(output); }

Přičemž u A) se mi pozadí aktualizuje okamžitě po kliknutí - tedy moc brzy; a při variantě B) zase moc pozdě.
A když zpozdím animaci $('#pozadi').animate({ left: '100vw' }, 1500, 'swing'); více jak na 1s, tak se mi v cca polovině kousne, problikne a objeví se na pozici, kde animace končí (resp. animace není plynulá) Je to fukncí .load?

Opět budu rád, za jakoukoliv radu. :-)
DarkMeni
Profil
Jaká má být animace? Div s pozadím má zajet za pravý okraj a vrátit se s novým pozadím? Nebo se má nové sunout těsně za starým, nebo se má nové plynule zviditelnit zatímco se staré schovává?

V prvním případě na to bude stačit jeden div pro pozadí, v ostatních budou potřeba 2 divy pro nové a staré pozadí.
Trax
Profil
DarkMeni:
Ta první možnost. :-) Tedy zajede za pravý okraj a od stejného okraje vyjede už aktualizované / nové pozadí.
DarkMeni
Profil
Zkus tohle
var Bg = $(this).attr('href');
$('#pozadi').data('new-bg', Bg);

$('#pozadi').animate({ left: '100vw' }, 1500, 'swing',

  function(){ /* on complete */
    var pozadi = $("#pozadi");
    var new_Bg = pozadi.data("new-bg");
    pozadi.css('background-image', 'url(/TraxartSystem/galerie/bg_' + new_Bg + '.jpg)');
    pozadi.animate({left: '0vw'}, 1500);
  }
  
);
(plus mínus, zase, nezkoušel sem, ale jakože teorie je taková, že nechat doběhnout tu animaci - protože i když nastavíš že má trvat 1500ms, tak není jistý, že opravdu bude trvat těch 1500ms, proto je tam ten callback on complete, a tam se pak změní pozadí a spustí se další animace, která to vrátí zpátky)

A možná, jestli jsou ty obrázky velký, tak je všechny hned po načtení stránky preloadnout.
Trax
Profil
DarkMeni:
Nu, kdybych byl s JS trochu větší kamarád, tak bych snad něco zbastlil. V tomto případě pozadí zajede za pravou stranu obrazovky, ale už nevyjede a jen problikne. Netuším, kde by mohla být chyba. :-)
DarkMeni
Profil
Hoď sem odkaz na živou ukázku
Trax
Profil
zjednodušená ukázka: jsfiddle.net/psmxgfok

mám ale podezření, že to problikává kvůli tomu, že momentálně mám v HTML u divu #pozadi style="background-image: url(a zde vypisuji cestu z DB);"
DarkMeni
Profil
Ok, takže pár věcí:
1) zvaž, jestli nepude místo position:absolute u #pozadi a overflow:hidden u body použít jen position:fixed u #pozadi, nebo nechat position:absolute ale obalit to ještě nějakým divem a tomu nastavit overflow:hidden, neboť scrollbary se u body můžou hodit, například na mobilu atd.

2) jQuer.load() (a.k.a. ajax) bude mít vždy nějaké spoždění, neboť se musí vytvořit spojení se serverem a stáhnout obsah, a nedá se předem říct, jak dlouhé to zpoždění bude, proto jsem se snažil poradit řešení, kde by nebyl použítý ajax. Ale jako i takle je to možný, proč ne, jen tam bude to nepředvídatelný zpoždění (někdy 10ms, někdy 100ms, někdy minutu když po cestě vypadne nějaký router xD i když s pravděpodobností možná tak 0,1% tak to asi není potřeba řešit)

3) zkus tohle: jsfiddle.net/psmxgfok/12
Ale nepodařilo se mi to rozchodit s tím load, nevím jestli je problém u jsfiddle nebo je tam někde chyba, každopádně, "load complete" callback se zavolá, ale nic to nenačte, jakože innerHTML od #stranka_preload je prázdný, tak to zkus u sebe na webu
Trax
Profil
DarkMeni:
Super.. Zkouším to teď na rychlo, ale vypadá to, že to funguje. :-) Děkuji. Nicméně měl bych ještě pár dotazů.

5. Na každé stránce se službou mám dvě tlačítka, které rozbalují takové ,,popup" okno.

function cist_otevrit() {$('.obsah_popup_info').animate({ width: '30vw', right: '303px', minWidth: '550px' }, 1000, 'swing');}
function cist_zavrit() {$('.obsah_popup_info').animate({ width: '0vw', right: '290px', minWidth: '0px' }, 1000, 'swing');}

function konverze_otevrit() {$('.obsah_popup_konverze').animate({ width: '30vw', right: '303px', minWidth: '550px' }, 1000, 'swing');}
function konverze_zavrit() {$('.obsah_popup_konverze').animate({ width: '0vw', right: '290px', minWidth: '0px'  }, 1000, 'swing');}

function popup_zavrit() {
$('.obsah_popup_info').animate({ width: '0vw', right: '290px', minWidth: '0px'  }, 1000, 'swing');
$('.obsah_popup_konverze').animate({ width: '0vw', right: '290px', minWidth: '0px'  }, 1000, 'swing');
}

$('.obsah span a').click(function() {konverze_zavrit(); cist_otevrit();});
$('.obsah_popup_info span a').click(cist_zavrit);
$('.konverze a').click(function() {cist_zavrit(); konverze_otevrit();});
$('.obsah_popup_konverze span a').click(konverze_zavrit);

Když načtu poprvé stránku, funguje. Jak ovšem překliknu na jakýkoliv odkaz v navigaci a načte se jiná stránka, tak nefunguje. Čím to může být?


6. Jsem rád, že jsi zmínil bod 2) dokud to mám takto rozkopané. Říkáš tedy, že by bylo lepší se od jQuery.load(); odklonit? Já to tak měl totiž již rozdělaný, tak jsem tvůj první příklad přenášel do toho, co jsem měl a tady ten problém mi tím pádem unikl. Taky musím říct, že mě trochu zmátla ta class aktivni, jelikož jsi zmiňoval, že by bylo 5 různých stránek (pochopil jsem to tak, že by tím pádem bylo 5 různých divů a jen jeden by neměl display:none) a já bych chtěl docílit toho, aby se mi ty stránky načítaly jen v jednom divu, jelikož se obávám, že do budoucna by jich přibylo.

7. Napadlo mě pár věcí a v souvislosti s tím by mě zajímalo, zda se dá PHP začlenit do JS tak jako do HTML. Pokud ano, dá se to i mimo index?

8. Byla by nějaká možnost načítat tu cestu toho pozadí z DB? - kompletní cestu, nebo alespoň celý název souboru (cesta se předpokládám měnit nebude), ale to je asi jedno..
DarkMeni
Profil
K 5., jestli sem nemůžeš dát odkaz se stránkou tak to budeš muset debugovat sám, což není vůbec složitý, stačí si otevřít javascript konzoli (u Firefoxu je to Ctrl+Shift+J u ostatních prohlížečů nevim) smazat co tam bylo do teď, ať to je trochu přehledný, refreshnout stránku, a sledovat co to vypisuje, vyvolat ten popup, a zase zkontrolovat jestli to nevypsalo nějakou chybu, a většinou to řekne i na jakém řádku byla způsobena a proč (undefined proměnná atd..)

Jinak bych tipoval, že pokud máš .obsah_popup_info a .obsah_popup_konverze v #stranka, který pak měníš obsah, tak to bude asi tím. Neboť když se ten html obsah přepíše, tak zaniknou i event vazby (onclick atd.) takže je bude potřeba znovu vytvořit.

K 6., to právě záleží na situaci
Použití ajaxu:
- když se obsah může každou chvíli měnit, a je potřeba aby uživatel viděl aktuální obsah
- když je potřeba něco zpracovat na serveru (javascript by to nezvládnul, a ani by to nebylo možné hodit na výstup už předzpracované, protože by toho bylo přehnaně moc, a kdy už se to bere jako "přehnaně moc" je taky otázka, třeba já bych to viděl tak, že do 50kB nezobrazeného obsahu je to ještě v pohodě)
- když už to nechceš předělávat :)

Nevýhody / problémy s ajaxem (asynchronous javascript and xml):
- je asynchronní, což není přímo nevýhoda, ale musí se pak pracovat přes callback funkce, protože se neví, kdy se dokončí požadavek

A taky, aby byl ajax efektivní, tak by bylo vhodné k tomu přizpůsobit i zpracování na straně serveru. Tedy, když pozná, že se jedná o ajax dotaz (například podle nějakého parametru v $_GET, třeba isset($_GET["chci-jen-obsah"])) tak aby na výstup poslal jen ten obsah a ne zase celou stránku

K 7., jestli chceš do javascriptu propašovat nějaký data, tak to můžeš udělat v jakémkoliv .php souboru
<script type="text/javascript">
// globalni promenna
data_z_php = "<?= $promenna ?>"; // <?= je alternativa za delší <?php echo
</script>

s tím souvisi 8. otázka:
<?php
// jestli nepouzivas PDO, tak z DB vysledku bude potreba udelat asociativni pole "stranka" => "url pozadi"
$pozadi_z_DB = $result->fetchAll(PDO::FETCH_KEY_PAIR);
?>
<script type="text/javascript">
pozadi = <?= json_encode($pozadi_z_DB); ?>; // json encode z doho udela rovnou js objekt a.k.a. asociativni pole pro js
</script>
Trax
Profil
5. Právě to nikde moc zveřejňovat zatím nechci. Ale po pár úkonech se domnívám, že je přesně chyba tam, kde říkáš. Alespoň se to tak chová.
Pokud chci znovu vytvořit ty eventy na onclick, tak stačí když ty funkce výše, tedy:
function cist_otevrit() {$('.obsah_popup_info').animate({ width: '30vw', right: '303px', minWidth: '550px' }, 1000, 'swing');}
function cist_zavrit() {$('.obsah_popup_info').animate({ width: '0vw', right: '290px', minWidth: '0px' }, 1000, 'swing');}
atd. přidám do funkce function str_zobraz() ....? Nebo jakým způsobem je mohu znovu vytvořit?

6. Určitě budu dodělávat login a na základě něj bude fungovat i kontaktní formulář, u kterého budu porovnávat vepsané data s daty v DB, tudíž počítám, že ajax bude potřeba.

8. Jelikož nevím, co je PDO, tak asi PDO nepoužívám. :D I když jeden nikdá neví... :D :D Tudíž tento skript asi použít nemohu, či ano? :)


Ještě se tedy prokousávám tím skriptem, s tím pozadím, ale vypadá to, že si s tím nějak poradím. :-)) (tedy až na ty eventy, na to vůbec nevím kudy)
DarkMeni
Profil
5. Ano, na konec funkce str_zobraz() přidáš:
function str_zobraz() {
  // zkopirovani obsahu preloaderu do viditelneho divu
  var obsah = $('#stranka_preload').html();
  $('#stranka').html(obsah);
  $('#stranka').data('ceka-na-nacteni', false);
  // vraceni divu s novou strankou
  $('#stranka').animate({ left: '0vw' }, 1000, 'swing');
  
  // Event Listenery:
  $('.obsah span a').click(function() {konverze_zavrit(); cist_otevrit();});
  $('.obsah_popup_info span a').click(cist_zavrit);
  $('.konverze a').click(function() {cist_zavrit(); konverze_otevrit();});
  $('.obsah_popup_konverze span a').click(konverze_zavrit);
}

8. PDO je objekt na vytváření dotazů pro databázi, podobně jako mysqli. Pravděpodobně používáš na práci s DB jedno z toho, takže asi mysqli.

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