兩個視窗如何實現通訊

清清飞扬發表於2024-05-12

From: https://blog.csdn.net/CRMEB/article/details/134398554

前言介紹
在工作中就出現的這種問題,開發的產品的頁面需要嵌入到公司中其他產品中,因為是不同的產品,屬於不同的系統,最簡單的方式就是iframe和window.open()的方式,我選擇的是window.open()的方式,因為實現的效果就是點選某個按鈕才顯示該頁面,使用window.open()的方式對於佈局都比較好控制,這時就有個問題了。因為開發產品頁面直接需要獲取該使用者在其他產品時的使用者資訊和產品資訊,就涉及到了如何傳遞資訊的問題了

window.open()的引數介紹
對於window.open()一般可以設定三個引數,這裡就簡單介紹了,如果需要更深入的瞭解就請自己查詢資料

第一個引數,開啟新視窗的url地址

第二個引數,給新視窗的名字(name),並不是新視窗在視窗顯示的title,在視窗下,透過window.name的方式拿到

這裡也可以設定_self(在舊視窗開啟新視窗),_blank(重新開啟新視窗,預設就是該模式)
第三個引數,設定開啟新視窗的寬高等

一般設定'left=100,top=100,width=400,height=400',四個引數,其他引數可能有瀏覽器相容問題
1
返回值——新視窗的window引用

這時就有個疑問了,在設定第二引數時,我又想設定_self又想給新視窗設定name怎麼辦?

可以使用如下方式:

var targetWindow = window.open('', '_self')
targetWindow.name = 'demo'
targetWindow.location.href = 'http://localhost:8081/'
1
2
3
你會想這樣寫這麼麻煩,下面這麼寫不就很簡單啊

var targetWindow = window.open('http://localhost:8081/', '_self')
targetWindow.name = 'demo'
1
2
URL 的實際獲取是延遲進行的,並在當前指令碼塊執行完畢後開始。視窗建立和引用資源的載入是非同步進行的。

在第一種方法中並沒有url的載入,所以視窗是已經建立了,再給這個視窗設定的name。第二種方法有url的非同步載入,該視窗並沒有被建立好,就給這個視窗設定name,自然就無效了。

1.使用url攜帶引數的形式
可能最容易想到的方式就是使用url上攜帶引數的形式了,但是這種方式對於傳遞多種資料是不方便的,而且安全性也是個問題

2.使用postMessage的方式(使用環境:Vue)
透過查詢資料發現了這種比較有意思的方式,這種方式竟然對於跨域也是可以解決的,這不正合我意。

postMessage常用引數

第一個引數,就是傳遞的訊息message,可以使用字串,資訊過多可以使用JSON.stringify()的方式
第二個引數,就是傳送的url地址,也可以使用*來代替,但是不安全
傳送方使用postMessage,接收方繫結message事件

window.addEventListener("message",(e) => {
// 判斷是否是舊視窗發過來的,這個if判斷是必須的,然後會多接收一些不想接收的訊息,就是資訊還沒有傳送過來,繫結message事件會有預設資訊
if (e.origin !== "http://localhost:8080") return;
// e.data——接收到的資訊
// e.origin——傳送發的url地址,如果沒有if判斷,就會返回接收方的url(預設資訊)
// e.source——傳送方的window引用,如果沒有if判斷,就會返回接收方的window(預設資訊)
// e.origin和e.source結合可以讓接收方向傳送方傳送資訊,從而達到雙向通訊
console.log(e.data)
})
1
2
3
4
5
6
7
8
9
我就直接介紹跨域的方式如何使用,對於同源的方式也可以使用該方式,也有其他方式。

我想要的,

舊視窗把資訊傳給新視窗
舊視窗

// http://localhost:8080/


<template>
<div id="app">
<button @click="open">開啟新視窗</button>
</div>
</template>

export default {
name: 'App',
data () {
this.targetWindow = null
return {
}
},
methods: {
open() {
this.targetWindow = window.open('http://localhost:8081/', '_blank', 'left=100,top=100,width=400,height=400')
// 為什麼加定時器,主要是為了防止window.open()非同步載入,頁面沒有載入出來,就把訊息傳送出去了,有更好的方式也可以使用其他方式
setTimeout(() => {
this.targetWindow.postMessage('舊視窗向新視窗傳送的訊息', 'http://localhost:8081/')
}, 1000)
}
}
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
新視窗

// http://localhost:8081/

<template>
<div id="app">
新視窗
</div>
</template>

export default {
name: 'App',
mounted() {
window.addEventListener("message",(e) => {
if (e.origin !== "http://localhost:8080") return;
//傳送方傳送的資訊
console.log(e.data)
})
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
舊視窗可以向新視窗發資訊,新視窗也可以傳送資訊給舊視窗
舊視窗

// http://localhost:8080/

<template>
<div id="app">
<button @click="open">開啟新視窗</button>
<button @click="sendNew">向新視窗傳訊息</button>
舊視窗接收到的資訊:{{ text }}
</div>
</template>

export default {
name: 'App',
data () {
this.targetWindow = null
return {
text: ''
}
},
mounted() {
window.addEventListener('message',(e) => {
if (e.origin !== "http://localhost:8081/") return;
console.log(e.data)
this.text += e.data
})
},
methods: {
open() {
this.targetWindow = window.open('http://192.168.3.76:8081/', '_blank', 'left=100,top=100,width=400,height=400')
setTimeout(() => {
this.targetWindow.postMessage('舊視窗向新視窗傳送的訊息', 'http://192.168.3.76:8081/')
}, 1000)
},
sendNew() {
this.targetWindow.postMessage('舊視窗透過按鈕傳送給新視窗的訊息', 'http://localhost:8081/')
}
}
}
</script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
新視窗

//http://localhost:8081/

<template>
<div id="app">
新視窗
<button @click="sendOld">向舊視窗傳送訊息</button>
<!-- 接收舊視窗傳送的訊息 -->
接收舊視窗傳送的訊息:{{ text }}
</div>
</template>

export default {
name: 'App',
components: {

},
data() {
this.oldWindow = null
this.oldOrigin = null
return {
text: ''
}
},
mounted() {
window.addEventListener("message",(e) => {
if (e.origin !== "http://localhost:8080") return;
this.text += e.data
this.oldWindow = e.source
this.oldOrigin = e.origin
})
console.log(window.name)
},
methods: {
sendOld() {
this.oldWindow.postMessage('新視窗透過按鈕給舊視窗傳送的訊息', this.oldOrigin)
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
看到這裡你可能發現有段程式碼很怪,為什麼有些資料宣告在return上面的,這麼做是因為讓這個資料失去響應式,如果宣告在return內是有響應式的,這時this.targetWindow = window.open()在控制檯會出現跨域的報錯。原因是因為給它賦值是開啟子視窗的window,賦值會就會監聽targetWindow,就相當於在父視窗去對子視窗做操作,就造成了跨域的問題。

3.使用window.name的方式傳遞資訊
利用window.open()的第二個引數,把資訊傳給新視窗

舊視窗

window.open('http://localhost:8081/','要傳遞的資訊')
1
新視窗

console.log(window.name)
1
總結
如果就是舊視窗傳遞資訊給新視窗,不需要新視窗給舊視窗傳遞資訊,且只傳一次,三種方式都可以,推薦使用第三種方式

如果想實現兩個視窗通訊的話,就使用第二種方式

完整專案附件:點此下載
————————————————

版權宣告:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處連結和本宣告。

原文連結:https://blog.csdn.net/CRMEB/article/details/134398554

相關文章