[toc]

Get the window and document of iframe

Page:


<iframe name="frameSon" id="frame" width="300px" height="300px" src="http://b.laihua.com:4444" frameborder="1"></iframe>

Copy the code
  1. throughcontentDocumentorcontentWindow:

const frame = document.getElementById('frame')

const fwindow = frame.contentWindow

const fdoc1 = frame.contentDocument

const fdoc2 = frame.contentWindow.document

Copy the code

  1. throughwindow.framesAnd iframenameProperty, which is what you get directlyThe window object of the iframe page:

const frame = window.frames['frameSon']

console.log(`frame:`,frame);

console.log(`frame.document:`,frame.document);

Copy the code

Read or call a method inside an iframe

If you want to read or manipulate the contents of an iframe, be sure to do so after the iframe has been loaded. If you call a method or variable before the iframe has been loaded, an error will occur. There are two ways to determine if an iframe is loaded:

  1. The iframe obtained in the first method is an iframeDOM element. You can directly determine the completion of iframe loading through the frame.onload callback

  2. The iframe obtained in the first way is the window object of the iframe, but there is no onload method, so you can use the current page window.onload callback or document.readyState==”complete” to determine

For example, we want to call the test method in the child iframe in two ways:

The first way:


const frame = document.getElementById('frame')

const fdoc = frame.contentDocument || frame.contentWindow.document

frame.onload = () = > {

console.log(`frame.contentWindow.test:`, frame.contentWindow.test);

frame.contentWindow.test()

}

Copy the code

The second way:


const frame = window.frames['frameSon']

const fdoc = frame.document

window.onload = () = > {

console.log(`frame.test:`, frame.test);

frame.test()

}

Copy the code

Cross-domain problems caused by two pages with the same primary domain but different secondary domain names obtaining each other’s DOM

The main page is A.baidu.com, and the b.baidu.com sub-page is introduced in the form of IFrame. The child page declared a global method test, call this method in the parent page found cross-domain:

In this case, the parent page and the iframe primary domain are the same, but the secondary domain is different. This can be resolved by setting document.domain to the same primary domain at the same time:

In addition, the cross-domain problem of cookies can also be solved by setting the same document.domain for pages with the same primary domain but different secondary domain. A Cookie is a small piece of information written by a server to a browser that can only be shared by web pages of the same origin. However, browsers allow cookies to be shared by setting document.domain.

The parent page:


<! DOCTYPEhtml>

<html lang="en">

<head>

<meta charset="UTF-8">

<meta http-equiv="X-UA-Compatible" content="IE=edge">

<meta name="viewport" content="Width = device - width, initial - scale = 1.0">

<title>Document</title>

</head>

<body>

<h1>page1</h1>

<iframe name="frameSon" id="frame" width="300px" height="300px" src="http://b.baidu.com:4444"

frameborder="1"></iframe>

</body>

<script>

document.domain = 'baidu.com'

const frame = window.frames['frameSon']

const fdoc = frame.document

window.onload = () = > {

console.log(`frame.test:`, frame.test);

frame.test()

}

</script>

</html>

Copy the code

Iframe subpage:


<! DOCTYPEhtml>

<html lang="en">

<head>

<meta charset="UTF-8">

<meta http-equiv="X-UA-Compatible" content="IE=edge">

<meta name="viewport" content="Width = device - width, initial - scale = 1.0">

<title>Document</title>

</head>

<body>

<h1>page2d</h1>

</body>

<script>

document.domain = 'baidu.com'

function test(){

console.log(222: ` `.222);

}

</script>

</html>

Copy the code

The call result was successful:

The two pages have completely different domain names

If two web pages have different sources, you can’t get each other’s DOM. For example, iframe is introduced and Windows opened by the window.open method. The Windows between them cannot communicate.

For example, the parent page is Baidu.com and the child page is Zijie.com. The parent page invokes the global method test in the child page.

The test global method is declared in the subpage:


function test(){

console.log(222: ` `.222);

}

Copy the code

The parent page introduces the child page with iframe and tries to call its test method:


<body>

<h1>page1</h1>

<iframe

name="frameSon"

id="frame"

src="http://zijie.com:4444"

width="300px"

height="300px"

frameborder="1">

</iframe>

</body>

<script>

const frame = window.frames['frameSon']

const fdoc = frame.document

window.onload = () = > {

console.log(`frame.test:`, frame.test);

frame.test()

}

</script>

Copy the code

Result error across domains:


(index):54 Uncaught DOMException: Blocked a frame with origin "http://baidu.com:3333" from accessing a cross-origin frame.

at window.onload (http://baidu.com:3333/:54:42)

Copy the code

PostMessage, fragment identifier, window.name, and the first two are described below:

window.postMessage

The window.postMessage method allows communication across Windows, whether or not the two Windows are homologous.

The approximate implementation logic is as follows:

A window can get a reference to another window (such as the contentWindow property of iframe, the window object returned by executing window.open, or the window.frames named or numeric index), Call the postMessage method on the window reference to distribute a MessageEvent message. The child window then listens for the message event to get the message from the parent window.

The child page sends messages to the parent window, except that the child window can get a reference to the parent window through messageEvent.source.

Grammar:


otherWindow.postMessage(message, targetOrigin);

Copy the code

OtherWindow: a reference to the target window to which to send a message;

The first argument, message, is the specific message content.

The second parameter, targetOrigin, specifies which Windows can receive message events. You can specify the origin of the receiving window, that is, “protocol + domain + port”. You can also set this parameter to “*”, indicating that the domain name is not limited and the message is sent to all Windows. If any of the protocol, host address, or port of the target window does not match the value provided by targetOrigin, the message will not be sent. A message will only be sent if all three match. This mechanism is used to control which Windows messages can be sent to.

When listening for message times, you can get the following three parameters from the MessageEvent object:

MessageEvent. Source indicates the window that sends the message. Origin indicates the source from which the message is sentCopy the code

How do we get throughpostMessageResolve the cross-domain issues that occur above:

When the parent page gets a reference to the child page, it calls its postMessage method and passes the method it needs to call as an argument:


window.onload = () = > {

frame.postMessage({ fn: 'test' }, "http://zijie.com:4444")}Copy the code

After listening for message time and making judgments about event.origin and event.data, call the corresponding methods:


function test(){

console.log(222: ` `.222);

}

window.onload = function(){

window.addEventListener('message'.e= > {

console.log(`e:`,e);

if(e.origin === 'http://baidu.com:3333' && e.data.fn === 'test'){

test()

}

})

}

Copy the code

Execution Result:

If the child page needs to notify the parent page after executing the method, it can obtain the reference of the parent page through event.source in the child page, call its poseMessage method, and then listen for message time in the parent page.

Child pages:


function test(){

console.log(222: ` `.222);

}

window.onload = function(){

window.addEventListener('message'.e= > {

console.log(`e:`,e);

if(e.origin === 'http://baidu.com:3333' && e.data.fn === 'test'){

test()

// Notify the parent page

e.source.postMessage('执行完毕'.The '*')}}}Copy the code

The parent page:


window.onload = () = > {

frame.postMessage({ fn: 'test' }, "http://zijie.com:4444")

// Accept sub-page notifications

window.addEventListener('message'.e= > {

console.log(`e.data:`,e.data); })}Copy the code

Execution Result:

aboutpostMessageSecurity issues

Do not add any event listeners for message events if you do not want to receive messages from other sites. This is a completely foolproof way to avoid security issues.

If you do want to receive messages from other sites, always verify the identity of the sender using the MessageEvent.origin and MessageEvent.source properties. Any window (including, for example, evil.example.com) can send messages to any other window,

When using postMessage to send data to other Windows, always specify the exact destination origin, not *. A malicious site can change the location of a window without our knowledge, so it can intercept data sent using postMessage.

Fragment Identifier

A fragment identifier is the part of a URL after the # sign. Such as “example.com/x.html#frag… The “# of fragments. If you just change the fragment identifier, the page does not refresh.

The parent page hashes the method to be called after the iframe address:


const frame = document.getElementById('frame')

window.onload = () = > {

// Changing the SRC of the iframe with the hash will not result in a refresh

frame.src = `http://zijie.com:4444#test`

}

Copy the code

The child page listens for the hashchage event to get the hash value of the current address:


function test(){

console.log(222: ` `.222);

}

window.onload = function(){

window.addEventListener('hashchange'.e= > {

console.log(`e:`,e);

// Use location.hash to get the information passed from the parent page

console.log(`window.location.hash:`.window.location.hash);

const fn = window.location.hash.slice(1)

eval(fn)()

})

}

Copy the code

Results:

Similarly, child Windows can change the fragment identifier of the parent window.


parent.location.href= target + "#" + hash;

Copy the code

REF

(9 messages) postMessage security issue _Exploit’s station ~-CSDN blog

Common front-end cross-domain solutions (including reverse proxies)_ bilibili _bilibili

Window. The reference | MDN postMessage – Web API interface

Using JS to iframe father and son (inside and outside) page operation method tutorial _javascript skills _ script home

Browser same Origin policy and its circumvention method – Ruan Yifeng’s network log