2012-02-04 23 views
8

Ho uno script shadowbox. Quando carico la pagina, tutto funziona correttamente, ma quando chiamo questa funzione di caricamento jquery e poi provo ad attivare la shadowbox facendo clic sull'immagine, l'immagine grande si apre in una nuova finestra. Ecco il codice:shadowbox smette di funzionare dopo la chiamata della funzione jquery

<link href="CSS/main.css" rel="stylesheet" type="text/css" /> 
<script type="text/javascript" src="shadowbox-3.0.3/shadowbox.js"></script> 
<script type="text/javascript"> 
Shadowbox.init(); 
</script> 

<p id="compas"><a href="images/coverage.jpg" rel="shadowbox" title="Coverage map"></a></p> 

Qualsiasi idea del perché questo sta accadendo?

+0

Che cosa significa la console degli errori (Firebug, console Chrome) rapporto?Probabilmente vorrai usare Persist. –

+0

Niente mostra. Le immagini si aprono in una nuova finestra ordinaria. – Igor

+0

Quello che vedo, non vedo nulla di sbagliato in sé. Avete un link? –

risposta

10

EDIT

Così, abbiamo finalmente arrivare in fondo a questa. 15 ore dopo aver prima commentato questo problema e almeno 50 iterazioni dopo, abbiamo finalmente identificato il problema e come risolverlo.

In realtà mi ha colpito improvvisamente quando stavo creando locale aaa.html e bbb.html sul mio server. È stato allora che mi ha colpito il fatto che i nodi elemento per il contenuto che veniva sostituito venivano rimossi del tutto dal DOM quando $.load() eseguiva la funzione di callback. Quindi, una volta che gli elementi di contenuto di #menu-home sono stati sostituiti, sono stati rimossi dal DOM e non è stato più applicato a Shadowbox.

Una volta ho capito questo, era solo una questione di una singola ricerca sul web e ho trovato:

Nabble-Shadowbox - Reinit Shadowbox

In particolare, la risposta da mjijackson. Ciò che egli descrive è come "restart" (reinizializzare) Shadowbox utilizza:

Shadowbox.clearCache(); 
Shadowbox.setup(); 

Quindi una volta che il contenuto #menu-home è stata ricaricata, ciò che deve accadere è la cache Shadowbox deve essere cancellata (in sostanza, chiuderlo sul pagina), viene eseguito il Shadowbox.setup(), che rileverà gli elementi da capo. Non si esegue nuovamente il metodo Shadowbox.init().

Ho notato che si era tentato di copiare/incollare lo Shadowbox.setup() dopo lo $.load(), almeno in sequenza nel codice. Tuttavia, questo non ha funzionato, a causa della cancellazione della cache che deve avvenire prima, e principalmente perché le funzioni .clearCache() e .setup() devono essere eseguite dopo il $.load() completa (termina ed esegue tutte le richiamate). Queste due funzioni devono essere eseguite nel gestore di callback $.load(); in caso contrario, è in esecuzione, ma lo $.load() è asincrono e verrà completato in un secondo momento.

Ho intenzione di andare oltre alcune altre modifiche che ho fatto, solo così capisci cosa, perché e perché.

nota, non sono sicuro se si ha familiarità con <base>, ma quanto segue è in cima dell'elemento HEAD:

<base href="http://62.162.170.125/"/> 

Questo solo diamo è possibile utilizzare i file di risorse sul computer. Non vorrai usare questo sul tuo sito attuale più che probabile. Se copi/incolli, assicurati di rimuovere questa riga.

<div id="menu"> 
    <ul> 
    <li><a id="menu-home" href="index.html" rel="http://jfcoder.com/test/homecontent.html">Home</a></li> 
    <li><a id="menu-services" href="services.html" rel="http://jfcoder.com/test/servicescontent.html">Services</a></li> 
    <li><a id="menu-tour" href="tour.html" rel="http://jfcoder.com/test/tourcontent.html">Tour</a></li> 
    <li><a id="menulogin" href="login.html">Login</a></li> 
    </ul> 
</div> 

Qui, si noterà che ho un URL relativo nell'attributo HREF, e un link ad alcune pagine sul mio server. Il motivo dei link al mio server è che non ho potuto accedere ai tuoi file aaa.html e bbb.html tramite AJAX a causa di limiti di scripting cross-site. Anche i link al mio sito web dovrebbero essere rimossi.

Ora, la ragione per cui sto usando il rel attributo qui è che voglio permettere i collegamenti a titolo dell'attributo href di continuare a lavorare nel caso in cui il JS non funziona correttamente o c'è qualche altro errore. Se hai file separati, uno per il documento HTML completo e un altro per i soli frammenti, questo è ciò che vorresti fare. Se puoi pubblicare sia il documento completo che il contenuto, solo dal file collegato, probabilmente non hai bisogno dell'attributo rel, ma dovrai gestire la richiesta in modo che il server sappia come rispondere (documento completo o solo la parte del contenuto).

var boxInitialize = function(){ 
    try { 
     if (!Shadowbox.initialized) { 
      Shadowbox.init(); 
      Shadowbox.initialized = true; 
     } else { 
      Shadowbox.clearCache(); 
      Shadowbox.setup(); 
     } 
    } catch(e) { 
     try { 
      Shadowbox.init(); 
     } catch(e) {}; 
    } 
}; 

Tutto quello che ho fatto qui è creare una posizione centrale per le richieste di inizializzazione/impostazione. Abbastanza semplice. Nota, ho aggiunto la proprietà Shadowbox.initialized in modo da poter tenere traccia di se il Shadowbox.init() aveva eseguito, che può essere eseguito solo una volta. Tuttavia, tenere tutto in un posto è una buona idea, se possibile.

Ho anche creato una funzione di variabile che può essere definito sia come una normale funzione:

boxInitialize(); 

O come un riferimento alla funzione:

window.onload = boxInitialize; // Note, no() at the end, which execute the function 

probabilmente noterete ho tolto il $() e li ha sostituiti con jQuery() invece. Questo può trasformarsi in un vero incubo se si finisce con un ambiente con più framework e librerie in competizione per $(), quindi è meglio evitarlo. Questo in realtà mi ha fatto davvero bene l'altro giorno.

Poiché abbiamo un ambito di chiusura all'interno del callback .ready(), possiamo trarne vantaggio per salvare diverse variabili "private" per l'uso in tempi diversi nell'esecuzione degli script.

var $ = jQuery, 
    $content = jQuery("#content"), // This is "caching" the jQuery selected result 
    view = '', 
    detectcachedview = '', 
    $fragment, 
    s = Object.prototype.toString, 
    init; 

Annotare il , alla fine di tutti, ma l'ultima riga. Guarda come ho "importato" lo $ rendendolo uguale alla variabile jQuery, il che significa che potresti effettivamente usarlo in quel #.

var loadCallback = function(response, status, xhr){ 
    if (init != '' && s.call(init) == '[object Function]') { 
     boxInitialize(); 
    } 

    if (xhr.success() 
      && view != '' 
      && typeof view == 'string' 
       && view.length > 1) { 
     $fragment = $content.clone(true, true); 
     cacheContent(view, $fragment); 
    } 
}; 

Questo viene eseguito quando il $.load() completa il processo della richiesta AJAX. Nota, il contenuto restituito nella richiesta è già stato inserito nel DOM al momento dell'esecuzione. Si noti inoltre che stiamo memorizzando il contenuto memorizzato nella cache nello $content.data(), che non dovrebbe mai essere rimosso dalla pagina; solo il contenuto sottostante.

var cacheContent = function(key, $data){ 
    if (typeof key == 'string' 
      && key.length > 1 
      && $data instanceof jQuery) { 
     $content.data(key, $data.html()); 
     $content.data(detectcachedview, true); 
    } 
}; 

cacheContent() è un metodo che potresti non volere; in sostanza, se è già stato caricato su una richiesta precedente, verrà memorizzato nella cache e quindi recuperato direttamente anziché avviare un altro $.load() per ottenere il contenuto dal server. Potresti non volerlo fare; In tal caso, basta commentare il secondo blocco if nella funzione menuLoadContent().

var setContent = function(html){ 
    $content.empty().html(html); 

    if (init != '' && s.call(init) == '[object Function]') { 
     boxInitialize(); 
    } 
}; 

Quello che fa è prima vuoto l'elemento $content del suo contenuto/elementi, quindi aggiungere il markup basato sulle stringhe specificato che abbiamo salvato in precedenza ottenendo il $content.html(). Questo è ciò che aggiungeremo nuovamente quando possibile; è possibile vedere una volta che i diversi collegamenti sono stati cliccati e caricati, facendo nuovamente clic per ottenere che la visualizzazione sia rapida. Inoltre, se è la stessa richiesta attualmente caricata, salterà anche l'esecuzione del codice del tutto.

(Usiamo $content come perché è un riferimento a una variabile contenente un elemento jQuery. Lo sto facendo perché è in un ambito di chiusura, il che significa che non viene visualizzato nell'ambito globale, ma sarà .. a disposizione per le cose come i gestori di eventi

Cercare i commenti inline nel codice

var menuLoadContent = function(){ 
    // This is where I cancel the request; we're going to show the same thing 
    // again, so why not just cancel? 
    if (view == this.id || !this.rel) { 
     return false; 
    } 

    // I use this in setContent() and loadCallback() functions to detect if 
    // the Shadowbox needs to be cleared and re-setup. This and code below 
    // resolve the issue you were having with the compass functionality. 
    init = this.id == 'menu-home' ? boxInitialize : ''; 
    view = this.id; 
    detectcachedview = "__" + view; 

    // This is what blocks the superfluous $.load() calls for content that's 
    // already been cached. 
    if ($content.data(detectcachedview) === true) { 
     setContent($content.data(view)); 
     return false; 
    } 

    // Now I have this in two different spots; there's also one up in 
    // loadCallback(). Why? Because I want to cache the content that 
    // loaded on the initial page view, so if you try to go back to 
    // it, you'll just pickup what was sent with the full document. 
    // Also note I'm cloning $content, and then get it's .html() 
    // in cacheContent(). 
    $fragment = $content.clone(true, true); 
    cacheContent(view, $fragment); 

    // See how I use the loadCallback as a function reference, and omit 
    // the() so it's not called immediately? 
    $content.load(this.rel, loadCallback); 

    // These return false's in this function block the link from navigating 
    // to it's href URL. 
    return false; 
}; 

Ora, seleziono le voci di menu rilevanti in modo diverso non è necessario un $.click() dichiarazione separata per ogni elemento.; invece, seleziono lo #menu a[rel], che riceverà ogni a elemento nel menu che ha un rel="not empty rel attribute". Ancora una volta, si noti come io uso menuLoadContent qui come riferimento di funzione.

jQuery("#menu a[rel]").click(menuLoadContent); 

Poi, in fondo, ho eseguito il boxInitialize(); per impostare Shadowbox.

Fatemi sapere se avete domande.


Penso che potrei arrivare a fondo di questo. Credo che il difetto è il modo in cui si sta gestire la $.load() dei nuovi contenuti quando si fa clic una voce di menu, accoppiato con un'eccezione non rilevata ho visto avere a che fare con una iframe:

eccezione Uncaught: Unknown giocatore iframe

Questo Nabble-Shadowbox forum thread si occupa di questo errore. In realtà non lo sto più, tuttavia penso che sia venuto fuori con il clic sulla voce di menu tour.

Ora, quello che stai facendo per caricare il contenuto per le voci di menu non ha alcun senso. Stai richiedendo un intero documento HTML e quindi selezionando solo un elemento con class="content". L'unico vantaggio che posso vedere è che la pagina non si ricarica mai, ma devi prendere un altro approccio su come ottenere e visualizzare i dati che non implicano il download dell'intera pagina tramite AJAX e quindi provare a far analizzare jQuery fuori solo la parte che vuoi.

Credo che la gestione del contenuto caricando in questo modo sia la causa principale del problema, quindi lo switch $.load() interrompe la pagina in modi imprevisti.

Domanda: Perché non si collega semplicemente alla pagina effettiva e si salta tutta la fantasia $.load()? In termini di velocità, non produrrà più di un impatto, se non del tutto. Non ha senso usare AJAX come questo, quando potresti semplicemente collegarli allo stesso contenuto senza problemi.

Ci sono due alternative che consentirebbero di evitare di andata e ritorno pagina viene ricaricata:

  1. Imposta il tuo chiamate AJAX per richiedere solo la parte .content del markup se avete la bandiera ?contentonly=true nell'URL, non il intero documento HTML. Questo è il modo in cui è tradizionalmente fatto e di solito è relativamente semplice da fare se si dispone di un ambiente di scripting.

    $(".content").load('index.html?contentonly=true'); 
    

    Quindi il server risponde solo con la visualizzazione del contenuto richiesta.

  2. Servire tutti i punti di vista dei contenuti all'interno dello stesso documento HTML, poi mostrano a seconda dei casi:

    var $content = $('.content'); 
    $content.find('.content-view').hide(); 
    $content.find('#services-content').show(); 
    

    Non guardare come si dispone di un intero sacco di contenuti per fornire, in modo che il primo il caricamento della pagina probabilmente non avrà molto impatto con questo approccio particolare. Potrebbe essere necessario esaminare come precaricare le immagini, ma questa è una tecnica molto conosciuta con molti script e tutorial di qualità là fuori.

una di queste tecniche potrebbero utilizzare la tecnica #! (hashbang) per caricare il contenuto, anche se credo che ci sono alcuni problemi con questo per i motori di ricerca. Tuttavia, qui è un collegamento a una tecnica semplice che ho messo insieme qualche tempo fa:

http://jfcoder.com/test/hash.html

Inoltre, questo è solo un suggerimento, ma non si riferiscono al vostro elemento "contenuto" con un class, vale a dire , .content. Ci dovrebbe essere un solo elemento di visualizzazione del contenuto nel markup, giusto? Non ce n'è più di uno? Utilizzare un id="content"; questo è quello che gli attributi ID servono per fare riferimento a un singolo elemento. class sono pensati per raggruppare gli elementi secondo alcune caratteristiche che condividono, quindi sopra quando I .hide() le visualizzazioni di contenuto in linea (vedi n. 2), cerco tutti gli elementi class="content-view", che sono tutti simili (contengono markup di visualizzazione del contenuto). Ma la variabile $content dovrebbe fare riferimento a $('#content');. Questo è descrittivo di ciò che sono gli elementi.

+0

Preferirei collegare le pagine effettive, ma non è nei requisiti. Il client vuole che il contenuto cambi senza che la pagina si ricarichi. Sto richiedendo un'intera pagina HTML e selezionandone il contenuto perché stavo pensando di inserire il link effettivo nelle href del menu, quindi se il browser di alcuni utenti non supporta javascript, funzionerebbe comunque. – Igor

+0

AJAX non si trasformerà in un comportamento simile a un collegamento, non farà nulla (incluso non attivare un caricamento di pagina completo). È necessario accettare la risposta con il documento HTML completo (richiesta di round trip regolare GET, come se si fosse fatto clic su un collegamento) o solo il frammento da visualizzare (la parte del contenuto) durante una richiesta AJAX. Puoi farlo con un flag GET su AJAX; basta omettere il flag dall'URL dell'attributo 'href', quindi verrà visualizzato nella pagina intera. Quindi, sullo script del server, rileva se è necessario rispondere con il documento HTML completo o con il solo contenuto. –

+0

Visualizza [questa demo] (http://www.asp.net/ajaxLibrary/jQueryCodeSamplesWebForms/jQueryLoad/MainContentForm.aspx) con Firebug o la console di rete di Chrome aperta e quando viene richiesta la frammentazione della pagina, visualizza la risposta il testo era Vedrai che è solo un frammento HTML, non un documento completo. –

1

questo ha funzionato per noi, abbiamo fatto un sito che ha usato le schede verticali e chiamò le pagine con le nostre immagini Shadowbox utilizzando jQuery.load

Basta dare tutto il vostro ancoraggio tag il class = "sbox" e incolla questo script nell'intestazione.

<script> 
    Shadowbox.init({ 
    skipSetup:true, 
}); 
$(document).ready(function() { 
    Shadowbox.setup($('.sbox'));//set up links with class of sbox 
    $('a.sbox').live('click',function(e){ 
     Shadowbox.open(this); 
     //Stops loading link 
     e.preventDefault(); 
    }); 
}); 
</script> 

Nota: abbiamo dovuto mettere la classe .sbox su tutti i nostri rel = "shadowbox" ancoraggi, nonché la sull'ancoraggio per la scheda che ha chiamato il .load

Grazie a questo ragazzo- >http://www.webmuse.co.uk/blog/shadowbox-ajax-and-other-generated-content-with-jquery-and-javascript/

0

Bene, sulla base della risposta di Shem, questa è la mia soluzione. Ogni click sulla classe specifica, configurazione e shadowbox aperta con elementi provenienti stessa classe:

jQuery('.sb-gallery a').live('click',function(e){ 
    Shadowbox.setup(jQuery('.sb-gallery a')); 
    Shadowbox.open(this); 
    //Stops loading link 
    e.preventDefault(); 
}); 

Grazie a tutti

Problemi correlati