shadowbox перестает работать после вызова функции jquery - PullRequest
8 голосов
/ 05 февраля 2012

У меня есть скрипт shadowbox. Когда я загружаю страницу, все работает нормально, но когда я вызываю эту функцию загрузки jquery, а затем пытаюсь вызвать shadowbox, нажав на изображение, большое изображение открывается в новом окне. Вот код:

<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>

Есть идеи, почему это происходит?

Ответы [ 3 ]

10 голосов
/ 05 февраля 2012

РЕДАКТИРОВАТЬ

Итак, мы наконец получаем основание этого.Через 15 часов после первого комментирования этой проблемы и, по крайней мере, через 50 итераций, мы наконец определили, в чем заключается проблема и как ее исправить.

Это на самом деле неожиданно меня поразило, когда я создавал local aaa.html иbbb.html на моем сервере.Именно тогда мне пришло в голову, что узлы элементов для заменяемого содержимого вообще удалялись из DOM, когда $.load() запускает функцию обратного вызова.Итак, после замены #menu-home элементов содержимого они были удалены из DOM, и к ним больше не применялся Shadowbox.

Как только я понял это, это был всего лишь один поиск в Интернете иЯ нашел:

Nabble-Shadowbox - Reinit Shadowbox

В частности, ответ от mjijackson .Он описывает, как «перезапустить» (переинициализировать) Shadowbox, используя:

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

Так что после перезагрузки контента #menu-home должно произойти очищение кэша Shadowbox (по сути, закрытиевниз на странице), затем запускается Shadowbox.setup(), который снова обнаружит элементы.Вы также больше не запускаете метод Shadowbox.init().

Я заметил, что вы пытались скопировать / вставить Shadowbox.setup() после $.load(), по крайней мере, последовательно в коде.Однако это не сработало из-за очистки кеша, которая должна произойти в первую очередь, и в первую очередь потому, что функции .clearCache() и .setup() необходимо запускать после завершения $.load() (заканчивает и запускает любые обратные вызовы).Эти две функции необходимо запустить в обработчике обратного вызова $.load();в противном случае вы запускаете его немедленно, но $.load() является асинхронным и завершится через некоторое время.

Я собираюсь рассмотреть некоторые другие сделанные мной изменения, просто чтобы вы поняли, что, почемуи поэтому.

Обратите внимание, я не уверен, знакомы ли вы с <base>, но в верхней части элемента HEAD указано следующее:

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

Thisпросто позвольте мне использовать файлы ресурсов на вашем компьютере.Вы не захотите использовать это на вашем реальном сайте более чем вероятно.Если вы копируете / вставляете, убедитесь и удалите эту строку.

<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>

Здесь вы заметите, что у меня есть относительный URL в атрибуте HREF и ссылка на некоторые страницы на моем сервере.Причиной ссылки на мой сервер является то, что я не смог получить доступ к вашим aaa.html и bbb.html файлам через AJAX из-за ограничений межсайтового скриптинга.Ссылки на мой веб-сайт также должны быть удалены.

Теперь я использую атрибут rel, потому что я хочу, чтобы ссылки через атрибут href продолжалиработать, если JS не работает правильно или есть какая-то другая ошибка.Если у вас есть отдельные файлы, один для полного HTML-документа, а другой только для фрагментов, это то, что вы хотите сделать.Если вы можете подать как полный документ, так и контент только из связанного файла, то вам, вероятно, не нужен атрибут rel, но вам нужно управлять запросом, чтобы сервер знал, как ответитьили только часть контента).

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

Все, что я здесь сделал, - это создание центрального расположения для запросов инициализации / настройки.Довольно просто.Обратите внимание, я добавил свойство Shadowbox.initialized, чтобы можно было отслеживать, запускался ли Shadowbox.init(), который можно запустить только один раз.Тем не менее, держать все это в одном месте - хорошая идея, если это возможно.

Я также создал переменную функцию, которую можно вызывать как обычную функцию:

boxInitialize();

Или как функциюссылка:

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

Вы, вероятно, заметите, что я удалил $() и заменил их на jQuery().Это может превратиться в настоящий кошмар, если вы получите среду с множеством фреймворков и библиотек, конкурирующих за $(), поэтому лучше избегать этого.Это на самом деле только что мне очень понравилось на днях.

Поскольку у нас есть область закрытия в обратном вызове .ready(), мы можем воспользоваться этим, чтобы сохранить несколько «приватных» переменных для использования в разное время при выполнении сценариев.

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

Обратите внимание на , в конце всех строк, кроме последней. Посмотрите, как я «импортировал» $, сделав его равным переменной jQuery, а это значит, что вы могли бы использовать его в этом #.

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);
    }
};

Он запускается, когда $.load() завершает процесс запроса AJAX. Обратите внимание, что содержимое, возвращенное в запросе, уже было помещено в DOM к тому времени, когда он выполняется. Также обратите внимание, что мы сохраняем фактический кэшированный контент в $content.data(), который никогда не должен удаляться со страницы; только содержимое под ним.

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() - это метод, который вам может не понадобиться; по существу, если он уже был загружен по предыдущему запросу, он будет кэширован, а затем получен напрямую вместо инициализации другого $.load() для получения содержимого с сервера. Вы можете не хотеть делать это; если это так, просто закомментируйте второй блок if в функции menuLoadContent().

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

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

Для этого сначала нужно очистить элемент $content его содержимого / элементов, а затем добавить указанную разметку на основе строк, которую мы сохранили ранее, получив $content.html(). Это то, что мы добавим, когда это возможно; Вы можете увидеть, как только ссылки были загружены и загружены, повторное нажатие, чтобы снова отобразить это, очень быстро. Кроме того, если это тот же запрос, который загружен в данный момент, он также пропустит выполнение кода в целом.

(Мы используем $content как, потому что это ссылка на переменную, содержащую элемент jQuery. Я делаю это, потому что он находится в области закрытия, что означает, что он не отображается в глобальной области видимости, но будет быть доступным для таких вещей, как обработчики событий.

Ищите встроенные комментарии в коде.

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;
};

Теперь я выбираю соответствующие пункты меню по-другому. Вам не нужно отдельное объявление $.click() для каждого элемента; вместо этого я выбираю #menu a[rel], который получит каждый элемент a в меню с rel="not empty rel attribute". Опять же, обратите внимание, как я использую menuLoadContent здесь как ссылку на функцию.

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

Затем в самом низу я запускаю boxInitialize();, чтобы настроить Shadowbox.

Дайте мне знать, если у вас есть какие-либо вопросы.


Я думаю, что могу понять все это. Я думаю, что недостаток заключается в том, как вы обрабатываете $.load() нового контента при нажатии на элемент меню, в сочетании с необъяснимым исключением, которое я видел при работе с iframe:

Неисследованное исключение: неизвестный игрок iframe

Эта ветка форума Nabble-Shadowbox имеет дело с этой ошибкой. На самом деле я больше этого не понимаю, однако думаю, что это получилось, я нажал на пункт меню tour.

Теперь то, что вы делаете для загрузки содержимого пунктов меню, на самом деле не имеет никакого смысла. Вы запрашиваете весь HTML-документ, а затем выбираете только элемент с class="content". Единственное преимущество, которое я вижу для этого, состоит в том, что страница никогда не перезагружается, но вам нужно использовать другой подход к получению и отображению данных, который не включает загрузку всей страницы через AJAX и затем попытку анализа jQuery для анализа. только ту часть, которую вы хотите.

Я полагаю, что обработка загрузки контента таким способом является основной причиной вашей проблемы, поэтому переключение представлений меню $.load() неожиданно нарушает вашу страницу.

Вопрос: Почему бы вам просто не дать ссылку на фактическую страницу и пропустить все причудливые $.load()? С точки зрения скорости, это не будет иметь большого значения, если таковое вообще будет. Просто не имеет смысла использовать AJAX таким образом, когда вы можете просто связать их с тем же контентом без проблем.

Существует две альтернативы, которые позволят вам предотвратить перезагрузку страницы в оба конца:

  1. Настройте вызовы AJAX так, чтобы запрашивать часть разметки .content только в том случае, если в URL есть флаг ?contentonly=true, а не весь документ HTML. Это то, как это традиционно делается, и, как правило, это относительно просто сделать, если у вас есть среда сценариев.

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

    Тогда ваш сервер отвечает только запрошенным просмотром контента.

  2. Обслуживать все представления содержимого в одном и том же HTML-документе, а затем показывать при необходимости:

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

    Не похоже, что у вас есть много контента для предоставления, поэтому начальная загрузка страницы, вероятно, не окажет такого большого влияния при этом конкретном подходе. Возможно, вам придется разобраться, как предварительно загружать изображения, но это очень хорошо известная техника со многими качественными сценариями и учебными пособиями.

Любой из этих методов мог бы использовать метод #! (hashbang) для загрузки контента, хотя я считаю, что для поисковых систем есть некоторые проблемы с этим. Однако вот ссылка на простую технику, которую я собрал некоторое время назад:

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

Кроме того, это всего лишь совет, но не ссылайтесь на ваш элемент «content» с class, т.е. .content. В разметке должен быть только один отображающий контент элемент, верно? Там не больше, чем один? Используйте id="content"; это то, для чего нужны ID атрибуты, чтобы ссылаться на один элемент. class предназначены для группировки элементов по некоторым характеристикам, которые они разделяют, поэтому выше, когда я .hide() рассматриваю встроенное содержимое (см. # 2), я ищу все элементы class="content-view", которые все похожи (они содержат разметка просмотра контента). Но переменная $content должна ссылаться на $('#content');. Это описание того, что это за элементы.

1 голос
/ 08 июня 2012

Это сработало для нас, мы создали сайт, который использовал вертикальные вкладки и вызывал страницы с нашими теневыми изображениями, используя jQuery.load

Просто присвойте всем вашим тегам привязки class = "sbox" и вставьте этот скрипт в заголовок.

<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>

Примечание: нам пришлось поместить класс .sbox на все наши якоря rel = "shadowbox", а также на якорь для вкладки, которая называется .load

Спасибо этому парню-> http://www.webmuse.co.uk/blog/shadowbox-ajax-and-other-generated-content-with-jquery-and-javascript/

0 голосов
/ 10 января 2014

Ну, исходя из ответа Шема, это мое решение.Каждый щелчок по определенному классу, настройка и открытие shadowbox с элементами из одного класса:

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

Спасибо всем

...