Back and forward buttons in an iframe

2019-01-13 13:26发布

问题:

How to "implement" back and forward buttons in an iframe with JS?

回答1:

Use the window.history object.

// For the current window
window.history.back();     
window.history.forward();

// For an iframe's window
iframe.contentWindow.history.back(); 
iframe.contentWindow.history.forward();

or

iframe.contentWindow.history.go(-1); // back
iframe.contentWindow.history.go(1);  // forward

https://developer.mozilla.org/en/dom/window.history



回答2:

Button within frame:

<input type="button" value="Back" onclick="history.back()">

Button within parent frame:

<input type="button" value="Back" onclick="frame_name.history.back()">


回答3:

Update for 2017: There is no way whatsoever to do this if the origin of the iframe content is different from the origin of the enclosing page - unless you control the content at the remote origin and can have it accept postMessage events. If the origin is the same, the older answers still work.



回答4:

Thanks everybody for your valuable pointers :-) I've managed to start from your suggestions and build on them a little further.

I have a webpage that has two vertical frames: a narrow column on the left for a menu bar (frame name="menu"), and a main window on the right (frame name="main"), spanning most of the width. I.e., the index.htm contains just a frameset across the whole surface. Now... to address the general "back" navigation problem in my simple frameset, I managed to use Pavel Strakhov's suggestion with input type=button - only I had to elaborate the DOM path a little further. As I have the button in the "menu" frame on the left, and the content to be navigated happens in the "main" frame on the right, the two frames are siblings, rather than a parent vs. child. Thus, in my case, I had to traverse one level up in the hierarchy, before I was able to refer to the sibling frame. As a result, in my case the button element reads

<input type="button" value="Back in the main frame" onclick="window.parent.main.history.back()">

or you can refer to the frame by ordinal index (zero-based) in an array, rather than by name:

<input type="button" value="Back in the main frame" onclick="window.parent.frames[1].history.back()">

I have also noticed that the whole 'onclick' property can be strapped onto pretty much any other visible element, such as an anchor/href (A), a DIV or a P. I've tried those as well, to make the "back" button look more like the rest of my menu, but ultimately went back to the crude "buttonish" look and behavior, to make the button more obvious / prominent / distinct. It looks raw but it works best.

Actually in my case, windows.parent actually refers to the top frame - so there's another way to refer to my frame called "main" and tell it to go back: onclick="top.main.history.back()" . Or, apparently, onclick="top.frames['main'].history.back()" .

And then I found out, that it still doesn't work reliably. Quirks discovered so far:

  • in Firefox around v42, if you go back and then use the browser's "forward" button, several more URL clicks down the road you can get funny results: sometimes the history.back() function in a frame will result in a history.back() on the top frame, for no apparent reason.

  • in Firefox around v42, sometimes the browser's own "back" button results in per-frame history.back(), rather than a top-frame history.back(), for no apparent reason (= inconsistent behavior of the native "back" button)

  • regardless of the browser make and version, some websites apparently clear the history of their base frame on site load. If you load such a site in a frame, the per-frame history.back() does nothing.

This is possibly another reason (apart from homogeneous styling) why hardly anyone uses the good old HTML frames anymore. The resulting behaviors are not very deterministic / foreseeable / obvious to the user. This is probably why webmasters prefer fixed columns, implemented by tables or by more modern means. Or perhaps it's just because everyone uses a CMS nowadays anyway.



回答5:

As others have mentioned, this is a major issue these days due to seemingly flawed security changes. In particular, as "mrec" says in a comment prior, The ugly problem here is that when your iframe is already at the start of its own history - and there's no way to detect this condition in script - doing another back() will effectively trigger a back() on the containing page instead, which is almost certainly not what you want. -- indeed, this was an insurmountable issue for me.

This solution is a tested version of the solution mentioned by responses here, whereby history is handled manually and the user cannot traverse back before history started. It was used in http://www.0AV.com for inline help and has been simplified here which may have introduced errors to the otherwise tested version. It will also likely need some refinement for your requirement.

JS in the host page..

var Hstory = [], sorc = '';

window.onmessage = function(e){ //# message fired by iFrame with onmousedown="window.top.postMessage('...','*');" or etc.
    var hilitedCrefText = e.data;    
    switch(String(hilitedCrefText)){
        case "Help_Home": //# defined in iframe
            sorc = "/index.html"; //# eg
            HistryManager(sorc); //# store
            break;
        case "Help_Back": //# defined in iframe
            sorc = HistryManager(); //# retrieve
            break;
        default: //# anything else that is generated by a link.
            HistryManager(sorc);
    }    
    if( sorc.length > 0 ) document.getElementById('your_iframe_id').src = sorc;  
}


function HistryManager(toPush) { //# history_handler
    if (toPush != undefined) {
        Hstory.push(toPush);
    }else{
        if( Hstory.length > 1 ){
            var az = Hstory[Hstory.length-2]; //..
            //# -2 is: -1 as is base 1, + -1 as it just stored this location, so must go back to PRIOR locastion.
            Hstory = Hstory.slice(0, -1); // Reduce array (Use neg num to select from end of array)
            return az;
        }else{
            alert('End of history. \n\n(Can not go further Back).');
            return '';
        }
    }
} 

JS / HTML in the iframe page..

    <button onclick="window.top.postMessage('Help_Back','*');">Back</button>
    <button onclick="window.top.postMessage('Help_Home','*');">Home</button>

    <button onclick="window.top.postMessage('helppage1.html','*');">HelpOn1</button>
    <button onclick="window.top.postMessage('helppage2.html','*');">HelpOn2</button>

..last 2 are examples of links user can traverse into (and add to history), in this case as buttons, but easily changed to anchors.

Hope that helps someone. (Tip: I misspelled some of my vars to prevent confusion with system vars). Code is an addition to Codiad, and as such is MIT License.