我目前正在开发一个webapp,我希望父母的子窗口能够相互通信。我希望兄弟姐妹沟通的原因是因为不能保证父母会保持打开状态,因为父母会被iFramed带入Microsoft CRM,如果他们更改了他们的标签,家长会关闭(如果不是这样我会让父母处理通信。)
以下适用于Chrome,但不适用于IE,我想知道是否还有其他方法可以完成。
在父窗口中:
var children = new Array();
function openWindow(...){
children.push(window.open(...));
}
在子窗口中:
var siblings = window.opener.children;
然后,如果父窗口关闭,此行仍然在chrome中工作,但不在IE
中siblings[0].close();
我还没有尝试过关闭以外的任何东西,但我相信所有功能都应该是可访问的(因为它们位于同一个域中)。它在Chrome中运行的事实对我来说是一个惊喜,但我们确实需要支持IE
修改
刚想到的一种方法是,当父级关闭以将子级的父级更改为其中一个子级时(IE父级将父级重新分配为子窗口)。但我不确定这是否有效甚至可能,因为我觉得它仍然会使引用消失
答案 0 :(得分:2)
好吧,我呕吐了一些东西尝试测试它,因为我以前从未听说过它。但是,它运作得很好。我有一个父窗口,可以跟踪它在数组中生成的窗口。然后每当它产生一个新窗口时,它会告诉孩子他们的新兄弟/姐妹,以便他们也可以跟踪他。然后每个孩子都有自己的方法,让他们从兄弟姐妹那里接收消息。我还给了他们简单的输入,以便能够互相发送消息并打印出他们收到的消息。
<强> Edit
强>
好的,完全重写了代码以使其更加健壮,因此您无需手动明确告诉孩子们彼此。现在,无论是loaded
还是unloaded
,父级都会挂钩事件,以便它可以告诉孩子它不再存在。这并不重要,因为孩子们在创建时会被告知彼此的存在。唯一有点棘手的是,如果你在父母关闭后创建更多的窗口。
父级通过ParentModule.spawnChild()
函数协调子级。这就是让孩子们了解新生儿的原因。因此,如果您想在父关闭后创建新窗口,则必须调整一些函数。但是,这里是父窗口和子窗口之间相互通信的代码,即使在父窗口关闭之后也是如此。请记住,这取决于same-origin policy
。
此外,还添加了一种让父母知道孩子何时关闭的方法。
<强>父强>
parent.html
<!DOCTYPE html>
<html>
<head>
<title>Parent</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<style></style>
<script src="parent.js"></script>
</head>
<body onload="main();" onunload="ParentModule.notifyChildren();">
<button id="closer">Close</button>
<div>New Child's Name</div>
<input type="text" id="newChildName">
<button id="spawner">Spawn Child</button>
<div id="log"></div>
</body>
</html>
parent.js
/**
* The namespace for the parent window
* @namespace ParentModule
*/
var ParentModule = (function() {
// Create an object to keep functions we want to be public
var exports = {};
/**
* The children windows
* @type Object
*/
exports.childWindows = {};
/**
* The number of children we have
* @type Number
*/
exports.numChildren = 0;
/**
* Create a new window and keep other windows in sync with the event
* @param {String} childName The name of the new child
* @returns {undefined}
*/
exports.spawnChild = function(childName) {
// Create a new window
var newChild = window.open(
"child.html",
childName,
"height=200, width=200, top=200, left=" + (200 * exports.numChildren)),
parent = window;
// Whenever the new window is finished loading, tell the window its
// name, its parent, and its siblings. Then tell the other children
// about their new siblings as well so that they can message him
// and mourn him if he gets closed.
newChild.addEventListener("load", function() {
// Log that the child was made
document.getElementById("log").innerHTML = "New child: " + childName;
// Tell the child its name
newChild.ChildModule.giveName(childName);
// Tell the child its parent
newChild.ChildModule.setParent(parent);
// Tell new child about its siblings
for (var child in exports.childWindows) {
newChild.ChildModule.addSibling(exports.childWindows[child], child);
}
// Tell all children about the new child
for (var child in exports.childWindows) {
exports.childWindows[child].ChildModule.addSibling(newChild, childName);
}
// Keep track of the new child yourself
exports.childWindows[childName] = newChild;
// Tell the child to say hi
newChild.ChildModule.start();
});
};
/**
* Function called whenever a child is closed
* @param {String} childName Child that is getting closed
* @returns {undefined}
*/
exports.removeChild = function(childName) {
var log = document.getElementById("log");
log.innerHTML = "My child: " + childName + " is gone";
delete exports.childWindows[childName];
};
/**
* Let all children know that you are being closed
* @returns {undefined}
*/
exports.notifyChildren = function() {
for (var child in exports.childWindows) {
exports.childWindows[child].ChildModule.removeParent();
}
};
/**
* Shortcut to be able to close all children
* @returns {undefined}
*/
exports.closeAllChildren = function() {
for (var child in exports.childWindows) {
exports.childWindows[child].close();
}
};
// Allow functions to get called
return exports;
}());
/**
* Function to setup the listeners
* @returns {undefined}
*/
function main() {
document.getElementById("spawner").addEventListener("click", function() {
ParentModule.spawnChild(document.getElementById("newChildName").value);
});
document.getElementById("closer").addEventListener("click", function() {
ParentModule.closeAllChildren();
});
}
儿童强>
child.html
<!DOCTYPE html>
<html>
<head>
<title>Child</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<style></style>
<script src="child.js"></script>
</head>
<body onload="main();" onunload="ChildModule.notifyKinOfDeath();">
<div>Destination Window</div>
<input type="text" id="whichWin">
<div>Message</div>
<input type="text" id="message">
<button id="sendMessage">Send Window a Message</button>
<div id="myName">I'm a child</div>
<div id="log"></div>
</body>
</html>
child.js
/**
* The namespace for the child window's functions
* @namespace ChildModule
*/
var ChildModule = (function() {
// Create an object to keep functions we want to be public
var exports = {};
/**
* The other siblings that this window should know about
* @type Object
*/
exports.siblingWindows = {};
/**
* This child's name
* @type String
*/
exports.name = "";
/**
* This child's parent
* @type Window
*/
exports.parent = null;
/**
* This function is written from the perspective of another window
* This is the way that another window can send THIS window a message
* @param {String} envelope Message for the child to get
* @returns {undefined}
*/
exports.sendMessage = function(envelope) {
var log = document.getElementById("log");
log.innerHTML = "Got: " + envelope.message + " from: " + envelope.sender;
};
/**
* This is written from the child's perspective
* This will actually send the message to the target sibling
* @param {String} targetSibling The sibling to message
* @param {String} message The message to send
* @returns {undefined}
*/
exports.passMessage = function(targetSibling, message) {
var log = document.getElementById("log");
if (exports.siblingWindows[targetSibling]) {
exports.siblingWindows[targetSibling].ChildModule.sendMessage({
"sender": exports.name,
"message": message
});
}
else {
log.innerHTML = "I have no sibling: " + targetSibling;
}
};
/**
* This function is written from the perspective of another window
* Give this child its name
* @param {type} name
* @returns {undefined}
*/
exports.giveName = function(name) {
exports.name = name;
document.getElementById("myName").innerHTML = "My name is: " + exports.name;
};
/**
* Function to get the child's name
* @returns {String}
*/
exports.getName = function() {
return exports.name;
};
/**
* Set the parent of this window
* @param {Window} parent The window that spawned this child
* @returns {undefined}
*/
exports.setParent = function(parent) {
exports.parent = parent;
};
/**
* What this child should do once started
* @returns {undefined}
*/
exports.start = function() {
var log = document.getElementById("log");
log.innerHTML = "Hello, my name is: " + exports.name;
};
/**
* Understand that a we have a new sibling that we can message
* @param {Window} sibling The new sibling
* @param {String} siblingName The name of the new sibling
* @returns {undefined}
*/
exports.addSibling = function(sibling, siblingName) {
var log = document.getElementById("log");
exports.siblingWindows[siblingName] = sibling;
log.innerHTML = "I have a brother named: " + siblingName;
};
/**
* Understand that a sibling has left us so we can't message them
* @param {String} siblingName Name of sibling that is gone
* @returns {undefined}
*/
exports.removeSibling = function(siblingName) {
var log = document.getElementById("log");
log.innerHTML = "My brother: " + siblingName + " is gone";
delete exports.siblingWindows[siblingName];
};
/**
* Understand that the parent has been closed
* @returns {undefined}
*/
exports.removeParent = function() {
var log = document.getElementById("log");
exports.parent = null;
log.innerHTML = "My parent is gone";
};
/**
* Whenever a child is unloaded, notify everyone of its death
* @returns {undefined}
*/
exports.notifyKinOfDeath = function() {
// Tell parent of your closing
if (exports.parent) {
exports.parent.ParentModule.removeChild(exports.name);
}
// Tell siblings of your closing
for (var sibling in exports.siblingWindows) {
exports.siblingWindows[sibling].ChildModule.removeSibling(exports.name);
console.log("I've told them");
}
};
// Allow functions to get called
return exports;
}());
/**
* Function to setup listeners
* @returns {undefined}
*/
function main() {
document.getElementById("sendMessage").addEventListener("click", function() {
// Get the message and the window to send to
var whichWin = document.getElementById("whichWin").value,
messageToSend = document.getElementById("message").value;
// Send the message
ChildModule.passMessage(whichWin, messageToSend);
});
}