简体   繁体   中英

Javascript - JQuery - clearInterval/setInterval - iframe cycle won't stop on click

I'm fairly new to Javascript in general, and I cobbled together a small script from things found mostly on this site to try to get a small iframe to cycle through a bunch of links, which it does brilliantly. However, I also want it to stop cycling when the user clicks on the iframe or any of its contents.

Here is the code I have so far. There is only one iframe on the HTML page.

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript" charset="utf-8">
<!--
var sites = [
  "side/html5.html",
  "side/silverlight.html",
  "side/wordpress.html",
  "side/mysql.html",
  "side/php.html",
  "side/css3.html"
];
var currentSite = sites.length;
var timerId;
var iframeDoc = $("iframe").contents().get(0);

$(document).ready(function ()
{
  var $iframe = $("iframe").attr("src","side/html5.html");

  timerId = setInterval(function()
  {
    (currentSite == 0) ? currentSite = sites.length - 1 : currentSite = currentSite -1;
    $iframe.attr("src",sites[currentSite]);
  }, 4000);

  $(iframeDoc).bind('click', function()
  {
    clearInterval(timerId);
  });

});
//-->
</script>
</head>

<body>

<sidebar>
<iframe name="sideframe" src="side/html5.html"></iframe>
</sidebar> ..etc..

Please help, I am trying to learn Javascript as fast as I can but as far as I can see, it should work, but it really doesn't.

Thanks for any help you can give me, it's really appreciated.


EDIT:

Okay, I've got a new script now, mostly based off of Elias' work, but it doesn't work either. I've pinned it down in Firebug and it's saying that the timerCallback.currentSite value IS updating properly, though I can't find the $iframe's src value to check for it explicitly. As far as I can tell, it is updating the variables properly, it's just not updating the iframe properly. Am I calling/setting the iframe correctly in this code? Also, is the linked in jquery library sufficient for my purposes? I'm a little lost of all these libraries to link to...

<script type="text/javascript" src="http://code.jquery.com/jquery.js"></script>
<script type="text/javascript" charset="utf-8">

<!--

var sites = 
[
  "side/html5.html",
  "side/silverlight.html",
  "side/wordpress.html",
  "side/mysql.html",
  "side/php.html",
  "side/css3.html"
];

var $iframe = $("iframe").attr("src","side/html5.html");

function timerCallback()
{
    timerCallback.currentSite = (timerCallback.currentSite ? timerCallback.currentSite : sites.length) -1;
    $iframe.attr("src",sites[timerCallback.currentSite]);

    $($('iframe').contents().get('body')).ready(function()
    {
        $(this).unbind('click').bind('click',function()
        {
            var theWindow = (window.location !== window.parent.location ? window.parent : window);
            theWindow.clearInterval(theWindow.timerId);
        });
    });

}

var timerId = setInterval(timerCallback, 4000);

//-->

</script> 

I think your code is not working because of this

var iframeDoc = $("iframe").contents().get(0);

This could be getting the header of the iFrame because you are saving the iframeDoc value to the first child of the iframe, the head tag, actually if you have more than 1 iframe in your window iframeDoc would be undefined because $("iframe") gets all the iframes of your document.

BTW your currentSite value condition is wrong, you asign the same value for both conditions

Now I give you an example:

<iframe id="myFrame" src="http://www.google.com/"></iframe>

and the script:

<script type="text/javascript" src="http://code.jquery.com/jquery.js"></script>
<script type="text/javascript">

var sites = [
"site1",
"site2"
];

var myFrame = document.getElementsByTagName('iframe')[0];
var currentSite = myFrame.getAttribute('src');
var timerId;

var myFrameDoc = window.frames[0].document;

$(document).ready(function()
{
    myFrame.setAttribute('src', 'side/html5.html');

    timerId = setInterval(function()
    {
        //WRONGG
        (currentSite == 0) ? currentSite = sites.length - 1 : currentSite = currentSite -1;
        myFrame.setAttribute('src', sites[currentSite]);
        $(myFrame).off("click").on("click", clearInterval(timerId));
    }, 4000);

    //Won't work because you are trying to get events from an inside of a iframe
    //$(myFrameDoc).on("click", clearInterval(timerId));
    //This may work
    $(myFrameDoc).off("click").on("click", clearInterval(timerId));
});

</script>

When you try to track the events of an iframe you have to be carefull because an iframe contains a totally different document for javascript purprouses so basically you have to get inside the new document, unbind the events you need to use, and bind them again against your functionality, as @Elias points out. but be aware that you are changing constantly the src of your iframe, so if yu really need to do that you will have to separate the code that unbinds and binds again your clearInterval, and for that matter maybe $.on() could work for you.

EDIT: Calling to the iframe should work this way IF the src of the iframe is inside the same domain, with the same port and with the same protocol:

var myFrameDoc = window.frames[0].document;

I Added a new variable because we want to bind and unbind the click event to the iframe's document, not to the iframe, we use for that the window.frames collection property, but modern browsers throw an exception and denies acces if you try to access to a frame and you are not on the same domain with using the same port and the same protocol...

Additionaly the use of $.on() and $.off() instead of $.bind and $.unbind() is because the first ones are the new ones and despite we are not using it here, they are capable of watch constantly the DOM for new elements to bind if added; that could be useful to this case if this code still doesn't work. If that is the case you can still change this:

var myFrameDoc = window.frames[0].window;

and this:

$(myFrameDoc).off("click", "document").on("click", "document", clearInterval(timerId));

This will re-bind the event handler to new documents additions. Not tested but could work.

If I were you, I'd play it safe. Since you say you're fairly new to JS, it might prove very informative.

function timerCallback()
{
    timerCallback.currentSite = (timerCallback.currentSite ? timerCallback.currentSite : sites.length) -1;
    $iframe.attr("src",sites[timerCallback.currentSite]);
}
var timerId = setInterval(timerCallback, 4000);
$($('iframe').contents().get('body')).unbind('click').bind('click', function()
{
    var theWindow = (window.location !== window.parent.location ? window.parent : window);
    theWindow.clearInterval(theWindow.timerId);
});

Now I must admit that this code is not tested, at all. Though I think it provides a couple of things to get you on your way:

1) the interval is set using a callback function, because it's just better for tons of reasons

1b) in that Callback, I took advantage of the fact that functions are objects, and created a static var, that is set to either the length of your sites array (when undefined or 0), in both cases 1 is substracted

2) jQuery's ,get() method returns a DOM element, not a jquery object, that's why I wrapped it in $() , a new jQ obj, giving you the methods you need.

3) since you're manipulating the dom inside the iFrame, it's best to unbind events you want to bind

4) inside the iFrame, you don't have direct access to the parent window, where your interval is.

You might want to read up on how to deal with iFrames, because they can be a bit of a faff from time to time

EDIT: David Diez is right, easiest way around this is to incorporate the binding in the timeout function:

function timerCallback()
{
    timerCallback.currentSide = ...//uncanged
    //add this:
    $($('iframe').contents().get('body')).ready(function()
    {
        $(this).unbind('click').bind('click',function()
        {
            //this needn't change
        });
    });
}

In theory, this should bind the click event to the body after it has been loaded

Edit2

I've been messing around a bit, you could keep your code, as is. just add a function:

function unsetInterval()
{
    window.clearInterval(window.timerId);
}

and add this to your setInterval function:

$('#idOfIframe').load(function()
{
    var parentWindow = window.parent;
    $('body').on('click',function()
    {
        parentWindow.clearInterval();
    });
});

this will get triggered as soon as the iFrame content is loaded, and bind the click event and unset the timer, like you wanted to

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM