2010-11-02 68 views
138

Cách đáng tin cậy nhất để giao tiếp Javascript giữa các tab/cửa sổ của cùng một trình duyệt là gì? Ví dụ, khi Tab 2 bắt đầu phát lại âm thanh, Tab 1 bằng cách nào đó biết về điều này và có thể tạm dừng trình phát của nó.Giao tiếp Javascript giữa các tab/cửa sổ trình duyệt

Tôi đang xây dựng một trang web có trình phát nhạc ... vì vậy tại thời điểm này nếu bạn mở hai tab vào trang web, bạn có thể bắt đầu phát nhạc trên cả hai. Điều này rõ ràng là xấu, vì vậy tôi đang cố gắng tìm một giải pháp.

Bất kỳ ý tưởng nào? Cảm ơn

+1

Tự động phát âm thanh là không có vấn đề gì. Tại sao không chỉ cho phép người dùng nhấp vào nút "phát" và tự tạm dừng tab khác nếu họ nhấn vào tình huống này? –

+7

Không có tự động phát. Nhưng sẽ rất tuyệt nếu người dùng không phải tạm dừng tab khác theo cách thủ công. Youtube thực hiện ví dụ này (với flash) – adamJLev

+5

+1 Câu hỏi hay, tôi đang giải quyết vấn đề chính xác này ngay bây giờ trong ứng dụng trò chuyện trên trang web của tôi. –

Trả lời

90

Bạn cũng có thể liên lạc giữa các cửa sổ trình duyệt (và các tab) bằng cookie.

Dưới đây là một ví dụ về người gửi và người nhận:

sender.html

<h1>Sender</h1> 

<p>Type into the text box below and watch the text 
    appear automatically in the receiver.</p> 

<form name="sender"> 
<input type="text" name="message" size="30" value=""> 
<input type="reset" value="Clean"> 
</form> 

<script type="text/javascript"><!-- 
function setCookie(value) { 
    document.cookie = "cookie-msg-test=" + value + "; path=/"; 
    return true; 
} 
function updateMessage() { 
    var t = document.forms['sender'].elements['message']; 
    setCookie(t.value); 
    setTimeout(updateMessage, 100); 
} 
updateMessage(); 
//--></script> 

receiver.html:

<h1>Receiver</h1> 

<p>Watch the text appear in the text box below as you type it in the sender.</p> 

<form name="receiver"> 
<input type="text" name="message" size="30" value="" readonly disabled> 
</form> 

<script type="text/javascript"><!-- 
function getCookie() { 
    var cname = "cookie-msg-test="; 
    var ca = document.cookie.split(';'); 
    for (var i=0; i < ca.length; i++) { 
     var c = ca[i]; 
     while (c.charAt(0)==' ') c = c.substring(1,c.length); 
     if (c.indexOf(cname) == 0) { 
      return c.substring(cname.length, c.length); 
     } 
    } 
    return null; 
} 
function updateMessage() { 
    var text = getCookie(); 
    document.forms['receiver'].elements['message'].value = text; 
    setTimeout(updateMessage, 100); 
} 
updateMessage(); 
//--></script> 
+2

Tôi nghĩ về một cái gì đó như thế này quá, nhưng đã hy vọng cho một giải pháp tốt hơn so với cookie/setTimeout. Tuy nhiên, đây có thể là giải pháp duy nhất. Thx – adamJLev

+0

bạn đang sử dụng loại trình phát nào? Nếu đó là trình phát flash, bạn có thể thực hiện các công cụ bằng flash có thể thanh lịch hơn. –

+0

Html5 với flash dự phòng – adamJLev

14

Tôi không nghĩ rằng bạn cần cookie. Mã js của mỗi tài liệu có thể truy cập các phần tử tài liệu khác. Vì vậy, bạn có thể sử dụng chúng trực tiếp để chia sẻ dữ liệu. W1 cửa sổ đầu tiên bạn mở W2 và lưu các tài liệu tham khảo

var w2 = window.open(...) 

Trong W2, bạn có thể truy cập vào W1 bằng thuộc tính mở của cửa sổ.

+2

SỬ DỤNG COOKIES? Ăn chúng và thưởng thức! Có một cách dễ dàng hơn! Chỉ cần truy cập vào một var của cửa sổ khác. Có một giá trị var trong w1, truy cập nó từ w2 whit window.opener.value! – donkeydown

+2

Giả sử người dùng mở tất cả. Bất kỳ giải pháp tương tự trong trường hợp đó? – Fardin

+0

Tôi nghĩ rằng bạn có thể mở bao nhiêu cửa sổ bạn muốn và sử dụng giải pháp này. Tham chiếu đến bất kỳ cửa sổ mới nào phải được đăng ký ở đâu đó. Tham chiếu đến cửa sổ chính luôn có sẵn. Tôi không thấy bất kỳ giới hạn nào cho đến nay. @Fardinak – donkeydown

-1

chỉnh sửa: Với Flash bạn có thể giao giữa bất kỳ cửa sổ, bất kỳ trình duyệt (có, từ FF IE khi chạy) Hình thức ..ANY sơ thẩm của đèn flash (ShockWave/activeX)

+5

Câu hỏi không phải về Flash. –

+1

Điều này sẽ không hoạt động trong hầu hết các trường hợp di động. – Soviut

+0

Để công bằng, Flash chạy "một dạng" Javascript giống như OP yêu cầu –

137

Đối với một giải pháp hiện đại hơn kiểm tra https://stackoverflow.com/a/12514384/270274

Trích:

tôi gắn bó với giải pháp dữ liệu địa phương chia sẻ đề cập trong câu hỏi sử dụng localStorage. Nó có vẻ là giải pháp tốt nhất về độ tin cậy, hiệu suất và khả năng tương thích của trình duyệt.

localStorage được triển khai trong tất cả các trình duyệt hiện đại.

Sự kiện storage kích hoạt khi các tab khác thực hiện thay đổi đối với localStorage. Điều này khá thuận tiện cho mục đích giao tiếp.

tham khảo:
http://dev.w3.org/html5/webstorage/
http://dev.w3.org/html5/webstorage/#the-storage-event

+3

Điều này tốt hơn so với giải pháp được chấp nhận. Điều này không yêu cầu bạn phải liên tục kiểm tra thông tin mới, không có sự chậm trễ và cho phép bạn nhận tất cả các sự kiện. –

+2

Tôi gặp sự cố với localStorage trên IE11, xem bài đăng này (i phải đối mặt với điểm số 3) http://blogs.msdn.com/b/ieinternals/archive/2009/09/16/bugs-in-ie8-support- for-html5-postmessage-sessionstorage-and-localstorage.aspx vì vậy việc giải quyết cockie tốt hơn (đối với IE ít nhất). Ngoài ra tôi đã cố gắng vô hiệu hóa cockies nhưng nó vẫn hoạt động (đây là trên IE 11). – Anas

+3

Trang demo tốt - http://html5demos.com/storage-events#view-source – HockeyJ

8

Giao tiếp giữa khác nhau bối cảnh thực thi mã JavaScript được hỗ trợ ngay cả trước khi HTML5 nếu tài liệu là của cùng một nguồn gốc. Nếu không hoặc bạn không có tham chiếu đến đối tượng khác Window, thì bạn có thể sử dụng API postMessage mới được giới thiệu với HTML5. Tôi đã xây dựng một chút về cả hai cách tiếp cận trong số stackoverflow answer này.

+4

API postMessage không được thiết kế cho http://stackoverflow.com/a/1100416/470117 Bạn cần tham chiếu cửa sổ được nhắm mục tiêu để đăng thông báo cho cửa sổ cụ thể đó – mems

1

Tìm thấy cách khác nhau sử dụng HTML5 localStorage, tôi đã tạo ra một thư viện với các sự kiện như API:

sysend.on('foo', function(message) { 
    console.log(message); 
}); 
var input = document.getElementsByTagName('input')[0]; 
document.getElementsByTagName('button')[0].onclick = function() { 
    sysend.broadcast('foo', {message: input.value}); 
}; 

nó sẽ gửi tin nhắn cho tất cả các trang khác nhưng không phải cho hiện tại.

+0

Bạn có thể thêm liên kết vào thư viện này không? –

+1

@DennisNerush https://github.com/jcubic/sysend.js – jcubic

9

Bạn có thể giao tiếp giữa các cửa sổ (theo tab hoặc không) nếu có mối quan hệ giữa cha và con.

Tạo và cập nhật một cửa sổ con:

<html> 
<head> 
<title>Cross window test script</title> 
<script> 
var i = 0; 
function open_and_run() { 
    var w2 = window.open("", "winCounter"); 
    var myVar=setInterval(function(){myTimer(w2)},1000); 
} 

function myTimer(w2) { 
    i++; 
    w2.document.body.innerHTML="<center><h1>" + i + "</h1><p></center>"; 
} 
</script> 
</head> 
<body> 
Click to open a new window 
<button onclick="open_and_run();">Test This!</button>  
</body> 
</html> 

cửa sổ Trẻ em có thể sử dụng đối tượng parent để giao tiếp với cha mẹ đã sinh ra nó, vì vậy bạn có thể kiểm soát các máy nghe nhạc từ một trong hai cửa sổ.

Xem hoạt động tại đây: https://jsbin.com/cokipotajo/edit?html,js,output

+0

Một vấn đề ở đây là, chúng tôi không thể (không bị hack) chia sẻ liên kết đến chế độ xem được đồng bộ hóa của chúng tôi ... – yckart

+0

@yckart Có rất nhiều cách để làm điều này nhưng cách phổ biến nhất mà tôi đã thấy là gửi chuỗi đến hộp nhập trong cửa sổ khác. Bạn có thể tạo trình xử lý sự kiện để thay đổi giá trị. Ví dụ: http://stackoverflow.com/questions/9994120/javascript-pass-selected-value-from-popup-window-to-parent-window-input-box. Tôi nghĩ sẽ tốt hơn nếu chỉ gọi một hàm javascript trong cửa sổ khác, chuyển nó qua URL. Ví dụ: từ cửa sổ con hoặc từ cửa sổ chính. –

11

Bạn có thể thực hiện việc này thông qua API bộ nhớ cục bộ. Lưu ý rằng thao tác này chỉ hoạt động giữa 2 tab. bạn không thể đưa cả người gửi và người nhận trên cùng một trang:

Trên trang sender:

localStorage.setItem("someKey", "someValue"); 

Trên trang thu

$(document).ready(function() { 

     window.addEventListener('storage', storageEventHandler, false); 

     function storageEventHandler(evt) { 
      alert("storage event called key: " + evt.key); 
     } 
    }); 
+0

Tôi sẽ sử dụng phương pháp này cho đến khi tôi phát hiện ra rằng điều khiển trình duyệt web không kích hoạt phương thức xử lý sự kiện "lưu trữ". Không chắc chắn lý do tại sao. Lỗi có lẽ. – Brain2000

+2

Cảm ơn giải pháp này. Làm cho ngày của tôi. Nó không hoạt động với tệp: /// protocol nhưng hoạt động với một miền hợp lệ. Một bản trình diễn tương tự khác http://html5demos.com/storage-events –

+2

Bạn không cần phải đợi DOM sẵn sàng để truy cập localStorage – meandre

7

Dưới cửa sổ (W1) mở ra một cửa sổ khác (W2). Bất kỳ cửa sổ nào cũng có thể gửi/nhận tin nhắn đến/từ cửa sổ khác. Vì vậy, chúng tôi lý tưởng nên xác minh rằng thông điệp có nguồn gốc từ cửa sổ (w2) chúng tôi đã mở.

Trong W1

var w2 = window.open("abc.do"); 
window.addEventListener("message", function(event){ 
    console.log(event.data); 
}); 

Trong W2 (abc.do)

window.opener.postMessage("Hi! I'm w2", "*"); 
+0

Câu trả lời hay, nó sẽ có nhiều phiếu bầu hơn. – VAdaihiep

+0

Tính năng này có hoạt động trên tất cả các trình duyệt không? –

5

Ngoài ra còn có một công nghệ thử nghiệm gọi là Broadcast Channel API được thiết kế đặc biệt để liên lạc giữa bối cảnh trình duyệt khác nhau với cùng một nguồn gốc. Bạn có thể gửi tin nhắn đến và tin nhắn nhận được từ một bối cảnh trình duyệt mà không cần phải một tham chiếu đến nó:

var channel = new BroadcastChannel("foo"); 
channel.onmessage = function(e) { 
    // Process messages from other contexts. 
}; 
// Send message to other listening contexts. 
channel.postMessage({ value: 42, type: "bar"}); 

Rõ ràng đây là công nghệ thí nghiệm và không được hỗ trợ accross tất cả các trình duyệt được nêu ra.

Các vấn đề liên quan