在jquery函数调用之后,shadowbox停止工作 [英] shadowbox stops working after jquery function call

查看:113
本文介绍了在jquery函数调用之后,shadowbox停止工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个shadowbox脚本。当我加载页面时一切正常,但是当我调用此jquery加载函数然后尝试通过单击图像触发阴影框时,大图像将在新窗口中打开。
这是代码:

I have a shadowbox script. When I load the page everything works fine, but when I call this jquery load function and then try to trigger the shadowbox by clicking on the image, the large image opens in new window instead. Here's the code:

<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次迭代后,我们终于确定了问题是什么以及如何解决它。

So, we finally get the bottom of this. 15 hours after first commenting on this issue, and at least 50 iterations later, we finally have identified what the problem is and how to fix it.

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

It actually struck me suddenly when I was creating local aaa.html and bbb.html on my server. That was when it hit me that the element nodes for the content that was being replaced was being removed altogether from the DOM when $.load() runs the callback function. So, once the #menu-home content elements were replaced, they were removed from the DOM and no longer had Shadowbox applied to them.

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

Once I figured this out, it was just a matter of a single web search and I found:

Nabble-Shadowbox - 重新启动Shadowbox

具体而言,来自 mjijackson 的回复。他描述的是如何使用以下方式重启(重新初始化)Shadowbox:

Specifically, the response from mjijackson. What he describes is how to "restart" (reinitialize) Shadowbox using:

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

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

So once the #menu-home content was reloaded, what needs to happen is the Shadowbox cache needs to be cleared (essentially, shutting it down on the page), then the Shadowbox.setup() is run, which will detect the elements all over again. You don't run the Shadowbox.init() method again either.

我注意到你曾尝试过在 $。load()之后复制/粘贴 Shadowbox.setup(),至少在代码中按顺序。但是,由于首先需要进行缓存清理,主要是因为 .clearCache(),因此无法正常工作。在 $。load()完成后完成(完成并运行任何回调)后,需要运行 code>函数 。这两个函数需要在 $ .load()回调处理程序中运行;否则,你正在立即运行它,但 $。load()是异步的,将在稍后完成。

I noticed that you had tried to copy/paste the Shadowbox.setup() in after the $.load(), at least sequentially in the code. However, this wasn't going to work, due to the cache clearing that needs to happen first, and primarily because the .clearCache() and .setup() functions need to be run after the $.load() completes (finishes and runs any callbacks). Those two functions need to be run in the $.load() callback handler; otherwise, you're running it's immediately, but the $.load() is asynchronous and will complete at some later time.

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

I'm going to go over some other changes I made, just so you understand what, why and wherefore.

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

Note, I'm not sure if you're familiar with <base>, but the following is at the top of the HEAD element:

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

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

This just let's me use the resource files on your computer. You'll not want to use this on your actual site more than likely. If you copy/paste, make sure and remove this line.

<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中有一个相对网址属性,以及指向我服务器上某些页面的链接。链接到我的服务器的原因是我无法访问您的 aaa.html bbb.html 文件由于跨站点脚本限制,通过AJAX。我的网站链接也应该删除。

Here, you'll notice I have a relative url in the HREF attribute, and a link to some pages on my server. The reason for the links to my server is that I couldn't access your aaa.html and bbb.html files through AJAX due to cross-site scripting limitations. The links to my website should be removed as well.

现在,我使用 rel 属性的原因这里是我希望允许通过 href 属性的链接继续工作,以防JS无法正常运行或出现其他一些错误。如果你有单独的文件,一个用于完整的HTML文档,另一个用于片段,这就是你想要做的。如果您可以同时提供完整文档和仅来自链接文件的内容,那么您可能不需要 rel 属性,但是您需要管理请求,以便服务器知道如何响应(完整文档或只是内容部分)。

Now, the reason I'm using the rel attribute here is that I want allow for the links by way of the href attribute to continue to work in case the JS doesn't function correctly or there's some other error. If you have separate files, one for full HTML document and another for just the fragments, this is what you'll want to do. If you can serve both the full document AND the content-only from the linked file, then you probably don't need the rel attribute, but you'll need to manage the request so the server knows how to respond (full document or just the content part).

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()是否已运行,只能运行一次。但是,如果可能的话,将它们保存在一个位置是个好主意。

All I've done here is create a central location for the initialization/setup requests. Fairly straightforward. Note, I added the Shadowbox.initialized property so I could keep track of if the Shadowbox.init() had run, which can only be run once. However, keeping it all in one spot is a good idea if possible.

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

I also created a variable function which can be called either as a regular function:

boxInitialize();

或作为函数参考:

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

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

You'll probably notice I removed the $() and replaced them with jQuery() instead. This can turn into a real nightmare if you end up with an environment with multiple frameworks and libraries competing for $(), so it's best to avoid it. This actually just bit me real good the other day.

因为我们在 .ready()回调,我们可以利用它来保存几个私有变量,以便在脚本执行的不同时间使用ow。

Since we have a closure scope within the .ready() callback, we can take advantage of that to save several "private" variables for ow use at different times in the scripts execution.

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

注意最后的但最后一行。通过使它等于jQuery变量,看看我如何导入 $ ,这意味着你可以在#中实际使用它。

Note the , at the end of all but the last line. See how I "imported" the $ by making it equal to the jQuery variable, which means you could actually use it in that#.

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

当$ code> $。load()完成AJAX请求的过程。请注意,请求中返回的内容在运行时已经放在DOM上。另请注意,我们将实际缓存的内容存储在 $ content.data()中,不应该从页面中删除;只有它下面的内容。

This runs when the $.load() completes the process of the AJAX request. Note, the content returned in the request has already been placed on the DOM by the time this runs. Note as well that we're storing the actual cached content in the $content.data(), which should never be removed from the page; only the content underneath it.

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()来从服务器获取内容。你可能不想这样做;如果是这样,只需在 menuLoadContent()函数中注释掉第二个 if 块。

cacheContent() is one a method you may not want; essentially, if it was already loaded on a previous request, then it will be cached and then directly retrieved instead of initiating another $.load() to get the content from the server. You may not want to do this; if so, just comment out the second if block in the menuLoadContent() function.

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

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

这样做首先清空 $ content 它的内容/元素的元素,然后通过获取 $ content.html()添加我们之前保存的指定的基于字符串的标记。这是我们在可能的情况下重新添加的内容;你可以看到一旦点击和加载不同的链接,重新点击以重新显示它是非常快的。此外,如果它与当前加载的请求相同,它也将完全跳过运行代码。

What this does is first empty the $content element of it's contents/elements, then add the specified string-based markup that we saved earlier by getting the $content.html(). This is what we'll re-add when possible; you can see once the different links have been clicked and loaded, reclicking to get that to redisplay is really quick. Also, if it's the same request as currently loaded, it also will skip running the code altogether.

(我们使用 $ content 喜欢因为它是对包含jQuery元素的变量的引用。我这样做是因为它在一个闭包范围内,这意味着它不会出现在全局范围内,但可用于事件之类的事情处理程序。

(We use $content like because it is a reference to a variable containing a jQuery element. I am doing this because it's in a closure-scope, which means it doesn't show up in the global scope, but will be available for things like event handlers.

在代码中查找内联注释。

Look for the inline comments in the code.

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 =非空的rel属性。再次,请注意我如何使用 menuLoadContent 作为函数参考。

Now, I select the relevant menu items differently. You don't need a separate $.click() declaration for each element; instead, I select the #menu a[rel], which will get each a element in the menu that has a rel="not empty rel attribute". Again, note how I use menuLoadContent here as a function reference.

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

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

Then, at the very bottom, I run the boxInitialize(); to setup Shadowbox.

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

Let me know if you have any questions.

我想我可能会深究这一点。我认为这个缺陷是你在点击一个菜单项时处理新内容的 $。load()的方式,加上我看到必须做的未捕获的异常使用 iframe

I think I might be getting to the bottom of this. I think the flaw is the way you're handling the $.load() of the new content when clicking a menu item, coupled with an uncaught exception I saw having to do with an iframe:


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

Uncaught exception: Unknown player iframe

Nabble-Shadowbox论坛帖子处理此错误。我实际上不再那样了,但我认为它是我点击了游览菜单项。

This Nabble-Shadowbox forum thread deals with this error. I'm actually not getting that anymore, however I think it came up with I clicked on the tour menu item.

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

Now, what you're doing to load the content for the menu items really doesn't make any sense. You're requesting an entire HTML document, and then selecting just an element with a class="content". The only benefit I can see for doing this is that the page never reloads, but you need to take another approach to how to get and display the data that doesn't involve downloading the entire page through AJAX and then trying to get jQuery to parse out just the part you want.

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

I believe handling the content loading this way is the root cause of your problem, hence the $.load() toggling of menu views breaks your page in unexpected ways.

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

Question: Why don't you just link to the actual page and skip all the $.load() fanciness? Speed-wise, it won't make that much of an impact, if any at all. It just doesn't make sense to use AJAX like this, when you could just link them to the same content without issue.

有两种选择可以让你防止往返页面重新加载:

There are two alternatives that would allow you to prevent roundtrip page reloads:


  1. 设置您的AJAX调用仅请求 .content 如果您在URL中有?contentonly = true 标志,而不是整个HTML文档,那么标记的一部分。这就是它传统上的做法,如果你有一个脚本环境,通常会相对简单。

  1. Setup your AJAX calls to only request the .content portion of the markup if you have the ?contentonly=true flag in the URL, not the entire HTML document. This is how it's traditionally done, and is usually relative simple to do if you have a scripting environment.

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

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

Then your server responds only with the content view requested.

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

Serve all of the content views within the same HTML document, then show as appropriate:

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

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

It doesn't look like you have a whole lot of content to provide, so the initial page load probably won't have that much of an impact with this particular approach. You might have to look into how to preload images, but that's a very well known technique with many quality scripts and tutorials out there.

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

Either one of these techniques could use the #! (hashbang) technique to load content, although I believe there are some issues with this for search engines. However, here is a link to a simple technique I put together some time ago:

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

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

Also, this is just a tip, but don't refer to your "content" element with a class, ie, .content. There should only be one content-displaying element in the markup, right? There's not more than one? Use an id="content"; that's what ID attributes are for, to reference a single element. classes are meant to group elements by some characteristic they share, so above when I .hide() the inline content views (see #2), I look for all of the class="content-view" elements, which are all similar (they contain content view markup). But the $content variable should refer to $('#content');. This is descriptive of what the elements are.

这篇关于在jquery函数调用之后,shadowbox停止工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆