择要
以下总结的跨文档通讯要领,均是在服务器不介入的情况下(服务端无需特别的代码)完成的
这里的通讯,是指页面A向页面B通报信息
大抵分为以下三类
- 经由历程 window.postMessage 完成双向通讯
经由历程客户端存储完成通讯
- cookie
- webStorage
- indexedDB
在页面跳转的历程当中照顾信息
- window.name
- Url 中 hash
- window.history.replace() && document.referrer
个中第一种要领没有跨域的限定,且完成的是双向通讯;第二种要领本质上应用的是同源文档能够接见统一块数据完成通讯;第三种要领只能完成定向的单次的通讯,且没有跨域的限定
经由历程 window.postMessage 完成通讯
搭建服务端
const http = require('http')
const fs = require('fs')
http.createServer((req, res) => {
fs.readFile(`.${req.url}`, (err, data) => res.end(data))
}).listen(8888)
编写文档 index1.html
...
<body>
index1
<button id='newWindow'>new Window</button>
<button id='sendMessage'>Send Message</button>
<script>
const newWBtn = document.getElementById('newWindow')
const sendBtn = document.getElementById('sendMessage')
let newWindow = null
newWBtn.addEventListener('click', () => {
newWindow = window.open(`${document.origin}/index2.html`)
})
sendBtn.addEventListener('click', () => {
newWindow.postMessage('messageFromIndex1', document.origin)
})
window.addEventListener('message', e => console.log(e.data), false)
</script>
</body>
...
编写文档 index2.html
...
<body>
index2
<script>
window.addEventListener('message', receiveMessage, false)
function receiveMessage(event){
console.log(event.data)
event.source.postMessage('messageFromIndex2', event.origin)
}
</script>
</body>
...
以上代码完成了经由历程 index1.html,新建窗口 index2.html
index1.html 向 index2.html 发送音讯 messageFromIndex1
index2.html 收到来自 index1.html 的音讯,并返回音讯 meesageFromIndex2
index1.html 和 index2.html 相互通报音讯的历程并不须要服务端介入
测试历程
启动服务器 node server.js
接见 http://localhost:8888/index1.html
前后点击 new Window 和 send Message,能够看到在 index1.html 和 index2.html 的掌握台平分别涌现了 messageFromIndex2 和 messageFromIndex1
补充
经由历程 postMessage 能够完成跨域的信息通报,因而也要注重通报信息的历程当中要搜检信息的安全性
经由历程客户端存储手腕完成通讯
将须要通报的信息保留在客户端中,只要同源的文档才接见,详细的完成体式格局有
- cookie
- webStorage
- IndexedDB
经由历程设置 cookie 举行通讯
当服务端没有设置 cookie 为 HttpOnly 时,能够在浏览器端设置和接见 cookie,而 cookie 本质上是服务器发送到用户浏览器并保留在浏览器上的一块数据,同源的文档能够接见 cookie
修正 index1.html
...
<body>
index1
<button id='newWindow'>new Tab</button>
<script>
const newWBtn = document.getElementById('newWindow')
newWBtn.addEventListener('click', () => {
document.cookie = 'name=test'
window.open(`${document.origin}/index2.html`)
})
</script>
</body>
...
修正 index2.html
...
<body>
index2
<script>
console.log(document.cookie)
</script>
</body>
...
能够看到在 index2.html 的掌握台中打印出了信息 ‘name=test’
经由历程 cookie 举行跨文档通讯,就像同源文档接见统一个对象
经由历程 webStorage 举行通讯
webStorage 就像一个数据库,同源的文档接见统一个子数据库
详细操作要领以下
window.localStorage.setItem(key, value)
window.localStorage.getItem(key)
经由历程 indexedDB 举行通讯
indexedDB 就是一个数据库
修正 index1.html
...
<body>
index1
<a href="./index2.html" target="_blank">index2.html</a>
<button id='addBtn'>add Data</button>
<button id='printBtn'>print Data</button>
<script>
let request = window.indexedDB.open('mydb', 2)
let time = 1
/* 建立objectStore和修正objectStore都只能在db的onupgradeneeded事宜中举行 */
request.onupgradeneeded = e => {
let db = e.target.result
if (!db.objectStoreNames.contains('mystore')) {
let objectStore = db.createObjectStore('mystore', {
keyPath: 'id'
})
objectStore.createIndex('id', 'id', {
unique: true
})
}
}
const addBtn = document.getElementById('addBtn')
const printBtn = document.getElementById('printBtn')
addBtn.addEventListener('click', () => {
// 翻开数据库
let request = window.indexedDB.open('mydb', 2)
request.onsuccess = e => {
// 翻开数据库 取得db
let db = e.target.result
let transaction = db.transaction(['mystore'], 'readwrite')
// 取得 objectStore 相当于数据库中的表
let objectStore = transaction.objectStore('mystore')
// 向表中增加字段
objectStore.put({
id: '100002',
name: `time_${time++}`,
})
}
})
printBtn.addEventListener('click', () => {
// 翻开数据库
let request = window.indexedDB.open('mydb', 2)
request.onsuccess = e => {
// 翻开数据库 取得db
let db = e.target.result
let transaction = db.transaction(['mystore'], 'readonly')
// 取得 objectStore 相当于数据库中的表
let objectStore = transaction.objectStore('mystore')
// 向表中增加字段
objectStore.get('100002').onsuccess = e => console.log(e.target.result)
}
})
</script>
</body>
...
修正 index2.html
...
<body>
index2
<button id='printBtn'>print Data</button>
<script>
const printBtn = document.getElementById('printBtn')
printBtn.addEventListener('click', () => {
// 翻开数据库
let request = window.indexedDB.open('mydb', 2)
request.onsuccess = e => {
// 翻开数据库 取得db
let db = e.target.result
let transaction = db.transaction(['mystore'], 'readonly')
// 取得 objectStore 相当于数据库中的表
let objectStore = transaction.objectStore('mystore')
// 向表中增加字段
objectStore.get('100002').onsuccess = e => console.log(e.target.result)
}
})
</script>
</body>
...
云云完成在 index1.html 中修正 indexedDB 中存储的数据时,index2.html 中也能够接见到,以此来间接完成通讯
页面跳转的历程当中照顾信息
以下这些要领都没有域的限定,但对跳转到新页面的体式格局有限定
经由历程 window.name 举行通讯
设置 window.name = message
当经由历程 window.location.href 或 <a href='./index2.html'>index2.html</a>
在当前窗口载入新页面时,window.name 仍保留着上个页面所设置的信息
修正 index1.html
...
<body>
index1
<a href="./index2.html">index2.html</a>
<script>
window.name = 'messageFromIndex1'
</script>
</body>
...
修正 index2.html
...
<body>
index2
<script>
console.log(window.name)
</script>
</body>
...
会在掌握台输出 messageFromIndex1
经由历程在 url 中增加 hash 字段
修正目的文档的 url,将想要通报的信息保留在 url 的 hash 字段中
经由历程 window.history.replace() 和 document.referrer
设置 window.history.replaceState(window.history,state, document.title, ‘message’)
从该页面到新页面后,经由历程 document.referrer 就能够看到来自上个页面的信息
修正 index1.html
...
<body>
index1
<a href="./index2.html" target="_blank">index2.html</a>
<script>
window.history.replaceState(window.history.state, document.title, 'messageFromIndex1')
</script>
</body>
...
修正 index2.html
...
<body>
index2
<script>
console.log(document.referrer)
</script>
</body>
...
会在掌握台输出 http://localhost:8888/messageFromIndex1
这里应用的是 window.history.replaceState() 修正 url,并不会使页面从新加载,所以将信息存在 url 中
document.referrer 会保留返回跳转或翻开到当前页面的谁人页面的 url