在jquery函数调用之后,shadowbox停止工作

Igo*_*gor 8 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>
Run Code Online (Sandbox Code Playgroud)

知道为什么会这样吗?

Jar*_*ish 10

编辑

所以,我们终于明白了这一点.首次评论此问题15个小时后,至少50次迭代后,我们终于确定了问题是什么以及如何解决问题.

当我在我的服务器上创建本地aaa.htmlbbb.html服务器时,它实际上突然袭击了我.就在那时我发现在$.load()运行回调函数时,正在被替换的内容的元素节点从DOM中被完全删除.因此,一旦#menu-home替换了内容元素,就会从DOM中删除它们,并且不再将Shadowbox应用于它们.

一旦我弄明白了,这只是一个网络搜索的问题,我发现:

Nabble-Shadowbox - 重新启动Shadowbox

具体来说,mjijackson的回应.他描述的是如何使用以下方式"重启"(重新初始化)Shadowbox:

Shadowbox.clearCache();
Shadowbox.setup();
Run Code Online (Sandbox Code Playgroud)

因此,一旦#menu-home重新加载内容,需要清除的是Shadowbox缓存(实质上是在页面上关闭它),然后Shadowbox.setup()运行,这将再次检测元素.您也不会Shadowbox.init()再次运行该方法.

我注意到您曾试图复制/粘贴Shadowbox.setup()后的$.load()代码,至少顺序.但是,这是行不通的,因为需要发生第一次,主要是因为在清除缓存.clearCache().setup()功能需要运行后,$.load()完成(完成并运行任何回调).这两个函数需要在$.load()回调处理程序中运行; 否则,你立即运行它,但它$.load()是异步的,将在稍后完成.

我将继续进行其他一些改变,让你明白为什么,为什么以及为什么.

注意,我不确定你是否熟悉<base>,但以下是HEAD元素的顶部:

<base href="http://62.162.170.125/"/>
Run Code Online (Sandbox Code Playgroud)

这只是让我使用您计算机上的资源文件.您不希望在实际网站上使用此功能.如果您复制/粘贴,请确保并删除此行.

<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>
Run Code Online (Sandbox Code Playgroud)

在这里,您会注意到我在HREF属性中有一个相对URL ,以及指向我服务器上某些页面的链接.究其原因,链接到我的服务器是,我无法访问您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) {};
    }
};
Run Code Online (Sandbox Code Playgroud)

我在这里所做的就是为初始化/设置请求创建一个中心位置.非常坦率的.注意,我添加了Shadowbox.initialized属性,所以我可以跟踪是否Shadowbox.init()已运行,只能运行一次.但是,如果可能的话,将它们保存在一个位置是个好主意.

我还创建了一个变量函数,可以作为常规函数调用:

boxInitialize();
Run Code Online (Sandbox Code Playgroud)

或作为功能参考:

window.onload = boxInitialize; // Note, no () at the end, which execute the function
Run Code Online (Sandbox Code Playgroud)

您可能会注意到我删除了$()并替换了它们jQuery().如果你最终得到一个有多个框架和库竞争的环境,这可能会变成一场真正的噩梦$(),所以最好避免它.这实际上只是让我在前几天真正的好.

由于我们在.ready()回调中有一个闭包范围,我们可以利用它来保存几个"私有"变量,以便在脚本执行的不同时间使用ow.

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

注意,除了最后一行之外的所有末尾.$通过使其等于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);
    }
};
Run Code Online (Sandbox Code Playgroud)

这在$.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);
    }
};
Run Code Online (Sandbox Code Playgroud)

cacheContent()是一种你可能不想要的方法; 实际上,如果它已经加载到先前的请求上,那么它将被缓存然后直接检索而不是启动另一个$.load()来从服务器获取内容.你可能不想这样做; 如果是这样,只需注释掉函数中的第二个ifmenuLoadContent().

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

    if (init != '' && s.call(init) == '[object Function]') {
        boxInitialize();
    }
};
Run Code Online (Sandbox Code Playgroud)

这样做首先清空$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;
};
Run Code Online (Sandbox Code Playgroud)

现在,我以不同的方式选择相关的菜单项.您不需要$.click()为每个元素单独声明; 相反,我选择了#menu a[rel],它将获得a菜单中具有的每个元素rel="not empty rel attribute".再次,请注意我menuLoadContent在这里如何用作函数引用.

jQuery("#menu a[rel]").click(menuLoadContent);
Run Code Online (Sandbox Code Playgroud)

然后,在最底部,我运行boxInitialize();设置Shadowbox.

如果您有任何疑问,请告诉我.


我想我可能会深究这一点.我认为缺点是你$.load()在点击一个菜单项时处理新内容的方式,再加上我看到与一个未被捕获的异常iframe:

未捕获的异常:未知的玩家iframe

这个Nabble-Shadowbox论坛帖子处理这个错误.我实际上不再那样了,但我认为它是我点击了tour菜单项.

现在,你正在做什么来加载菜单项的内容真的没有任何意义.您正在请求整个HTML文档,然后只选择一个带有的元素class="content".我可以看到这样做的唯一好处是页面永远不会重新加载,但你需要采取另一种方法来获取和显示不涉及通过AJAX下载整个页面然后尝试解析jQuery的数据只是你想要的部分.

我认为以这种方式处理内容是导致问题的根本原因,因此$.load()菜单视图的切换会以意想不到的方式破坏您的页面.

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

有两种方法可以防止往返页面重新加载:

  1. .content如果您?contentonly=true在URL中有标记而不是整个HTML文档,则将AJAX调用设置为仅请求标记的一部分.这就是它传统上的完成方式,如果您有脚本环境,通常会相对简单.

    $(".content").load('index.html?contentonly=true');
    
    Run Code Online (Sandbox Code Playgroud)

    然后,您的服务器仅响应请求的内容视图.

  2. 在同一HTML文档中提供所有内容视图,然后根据需要显示:

    var $content = $('.content');
    $content.find('.content-view').hide();
    $content.find('#services-content').show();
    
    Run Code Online (Sandbox Code Playgroud)

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

这些技术中的任何一种都可以使用#!(hashbang)技术来加载内容,但我相信搜索引擎存在一些问题.但是,这里有一个链接到我前面放在一起的简单技术:

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

此外,这只是一个提示,但不要引用你的"内容"元素class,即.content.标记中应该只有一个内容显示元素,对吧?不只有一个?用一个id="content"; 这就是ID引用单个元素的属性.classes意味着按照它们共享的某些特征对元素进行分组,所以当我.hide()在内联内容视图(参见#2)时,我会查找class="content-view"所有相似的元素(它们包含内容视图标记).但$content变量应该参考$('#content');.这描述了元素是什么.