Using relative url for window.location in child iframe

假如想象 提交于 2020-01-03 19:34:13

问题


I'm having trouble with an iframe-related issue.

I have a document (parent) with an iframe (child). If the parent document calls a function in the child which changes the childs url using window.location to a relative url, that url becomes relative to the parent document. Let me illustrate.

Parent document: /test/parent.html

Child document: /projects/child.html

Child code:

function moveOn(){
    window.location.href = "newPage.html";
}

Parent code:

childDocument.contentWindow.moveOn();

Result: Child document tries to access /test/newPage.html instead of /projects/newPage.html

Is there any way of fixing this from the parent? I am in a situation where I can't make changes in the child document code, only in the parent.

Thanks, Nik

Edit:

This is the actual code

In parent (/testr/testr.html):

testr.appHolder = $("childIframe"); 
testr.appHolder.src = "../projects/test.html"; 
testr.functionName = "moveOn"; 
testr.appHolder.contentWindow[testr.functionName]();

In child (/projects/test.html):

function moveOn(){ 
  window.location.href = "newPage.html"; 
}

This is the actual code

In parent (/testr/testr.html):

testr.appHolder = $("childIframe"); 
testr.appHolder.src = "../projects/test.html"; 
testr.functionName = "moveOn"; 
testr.appHolder.contentWindow[testr.functionName]();

In child (/projects/test.html):

function moveOn(){ 
  window.location.href = "newPage.html"; 
}

回答1:


Finally, a full solution!

childDocument.contentWindow.setTimeout( childDocument.contentWindow.moveOn, 0 );

This asks the child document to execute the given function (moveOn) in zero milliseconds, and it is executed in the context of the child, even in Internet Exploder.

Booyah.




回答2:


The HTML spec says:

When the [location property is set], the [browser] must resolve the argument, relative to the entry script's base URL, and if that is successful, must navigate the browsing context to the specified url.

One (hacky) way to get the behaviour you're after is to edit the pathname property of the location directly: effectively implementing the resolution of the relative url yourself.

In your case, you'd edit url "manually", using your child's existing url.

Dotdot solution

One "clever" way to do that is by appending a slash to turn the filename into a "directory", then erasing it with a "dotdot", followed by the relative url you want.

childDocument.contentWindow.location.pathname += "/../newPage.html";

(This code could also work within the child, but you mentioned you can't change the child code.)

Check out how this works.

The path starts as
/projects/child.html

Then you append to it, to get
/projects/child.html/../newPage.html

The browser resolves this to
/projects/newPage.html

Unfortunately, I imagine this won't be a perfect solution to you. Sounds like each of the "child" pages contain hard-coded links to the next page in the chain, which could be any page. Getting the "next" relative url for any given child page would require cooperation from the child.

If the child pages are named in a predictable way, and you know the total number of pages, and you know the base url of the child directory, you could have the parent control the child correctly. That's a lot of ifs.

Sidenote: I'm looking into a more elegant, robust solution. Fingers crossed.




回答3:


Aha. I've found the baseURI property. Now we're talking.

The fundamental problem is that the baseURI of the document which is executing the code (the parent) is set to the parent's location. You want to set the baseURI of the page to be the same as the child's location before you change it's location, so that the relative url is resolved in the context of the child.

In short, it would be great to say:

var originalURI = document.baseURI; // store for setting back after the move
document.baseURI = childDocument.location; // setting parent's baseURI (NO EFFECT!)
childDocument.contentWindow.moveOn();
document.baseURI = originalURI; // restore original baseURI

Unfortunately, the baseURI property is read only. Fortunately, its value is taken from the <base> tag, which you can alter with script. You can get the functionality you want for a given child by setting the parent's base tag to refer to the childUrl:

<head>
<base href="/path/to/child.html" />
</head>

Unfortunately, this makes any relative links in your parent relative to the child, which is not what you want. We need to set this just after clicking the link, and set it back after the child has been told to moveOn().

If you include an empty <base /> tag in your parent's <head>, it will not effect the baseURI by default. So when you want to execute the moveOn() function in the child, you can say something like:

var baseElement = document.getElementsByTagName("base")[0];

// adopt the child's location as baseURI
baseElement.href = childDocument.location; 

childDocument.contentWindow.moveOn();

// revert back to the parent's original baseURI
baseElement.removeAttribute("href"); 

(Hope this helps somehow - two years on... ha)

Edit:

Once again Internet Exploder is the party pooper. It seems that changes to any tag after load are not honoured. So unless you don't have to support IE (HA!), this solution won't work unless you're happy to hard code the child's location into the parent's tag. Again, those are big ifs.



来源:https://stackoverflow.com/questions/2280640/using-relative-url-for-window-location-in-child-iframe

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!