javascript - jQuery函数调用后,shadowbox停止工作

标签 javascript jquery shadowbox

我有一个shadowbox脚本。当我加载页面时,一切工作正常,但是当我调用此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>

知道为什么会这样吗?

最佳答案

编辑

因此,我们终于了解了这一点。在首次对此问题发表评论15个小时后,至少经过了50次迭代,我们终于确定了问题所在以及如何解决。

当我在服务器上创建本地aaa.htmlbbb.html时,它实际上突然使我震惊。那是当我感到惊讶的是,当$.load()运行回调函数时,正在替换的内容的元素节点已从DOM中完全删除。因此,一旦替换了#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/"/>

这只是让我使用您计算机上的资源文件。您不希望在实际网站上更多地使用它。如果您复制/粘贴,请确保并删除此行。
<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>

在这里,您会注意到HREF属性中有一个相对URL,以及指向服务器上某些页面的链接。链接到我的服务器的原因是由于跨站点脚本限制,我无法通过AJAX访问您的aaa.htmlbbb.html文件。我网站的链接也应删除。

现在,我在这里使用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()回调中具有闭包作用域,因此我们可以利用该作用域来保存几个“私有(private)”变量,以供脚本执行中不同时间使用。
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有关的未捕获异常:

Uncaught exception: Unknown player iframe



Nabble-Shadowbox forum thread处理此错误。我实际上已经不知道了,但是我认为是通过单击tour菜单项实现的。

现在,您为菜单项加载内容的操作确实没有任何意义。您需要一个完整的HTML文档,然后仅选择一个带有class="content"的元素。我看到的唯一好处是页面永远不会重新加载,但是您需要采取另一种方法来获取和显示数据,这并不涉及通过AJAX下载整个页面,然后试图让jQuery进行解析。只是您想要的部分。

我认为以这种方式处理内容加载是问题的根本原因,因此菜单 View 的$.load()切换会以意外的方式破坏您的页面。

问题:为什么不直接链接到实际页面并跳过所有$.load()的幻想?在速度方面,它不会产生太大的影响,即使有的话。当您可以将它们链接到相同的内容而不会出现问题时,使用这样的AJAX只是没有意义。

有两种选择可以防止往返页面重新加载:
  • 设置您的AJAX调用,仅在URL中包含.content标志而不是整个HTML文档的情况下,才请求标记的?contentonly=true部分。这是传统上的方式,如果您具有脚本环境,则通常相对简单。
    $(".content").load('index.html?contentonly=true');
    

    然后,您的服务器仅响应请求的内容 View 。
  • 服务于同一HTML文档中的所有内容 View ,然后根据需要显示:
    var $content = $('.content');
    $content.find('.content-view').hide();
    $content.find('#services-content').show();
    

    看起来您没有提供很多内容,因此初始页面加载可能不会对这种特定方法产生太大影响。您可能需要研究如何预加载图像,但这是一种非常知名的技术,其中包含许多高质量的脚本和教程。

  • 这些技术中的任何一种都可以使用#!(hashbang)技术来加载内容,尽管我认为搜索引擎存在一些问题。但是,这是我一段时间前组合在一起的一种简单技术的链接:

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

    另外,这只是一个提示,但是不要用class(即.content)引用“content”元素。标记中应该只有一个内容显示元素,对吗?不止一个?使用id="content";这就是ID属性的用途,以引用单个元素。 class旨在按照它们共享的某些特征对元素进行分组,因此,在上面我对内联内容 View .hide()进行编码(请参阅#2)时,我会寻找所有相似的class="content-view"元素(它们都包含内容 View 标记)。但是$content变量应该引用$('#content');。这是对元素的描述。

    关于javascript - jQuery函数调用后,shadowbox停止工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9144577/

    相关文章:

    javascript - 异步悖论BackboneJS

    javascript - 如何从 getter 中设置值?

    javascript - Shadowbox 未定义

    jquery - 点击overlay div激活shadowbox效果

    未检测到 Javascript 字符串比较

    javascript - 访问包含函数

    javascript - 在 JavaScript 中将一个枚举转换为另一个枚举

    javascript - jqGrid 免费 : Help on design of handling multiple yearly calendars with monthly breakdown data

    ajax - 通过对话框提交的表单再次打开对话框

    css - Shadowbox Firefox 滚动条不兼容问题