Проверьте, открыт ли мой сайт на другой вкладке
Я хочу проверить с помощью JavaScript, открыл ли пользователь мой сайт в другой вкладке своего браузера.
Кажется, я не могу сделать это с pagevisibility...
Единственный способ, который я вижу, - это использовать WebSocket на основе куки файла сессии и проверить, есть ли у клиента более одного сокета. Но, таким образом, из текущей вкладки я должен спросить мой сервер, есть ли у этого пользователя вкладка, открытая рядом с его текущей вкладкой браузера. Это немного надумано!
Может быть, с localstorage
?
Ответы
Ответ 1
Используя локальное хранилище, я создал простую демонстрацию, которая должна выполнить то, что вы хотите сделать. В принципе, он просто поддерживает подсчет открытых окон. Когда окно закрывается, выгружаются события и удаляются из общего количества окон.
Когда вы сначала смотрите на него, вы можете думать, что там происходит больше, чем есть на самом деле. Большая часть из них заключалась в попытке добавить логику к тому, кто был "главным" окном, и кто должен стать "основным" окном, когда вы закрыли детей. (Следовательно, setTimeout вызывает повторную проверку, если его следует продвигать в главное окно) После некоторой царапины на голове, я решил, что потребуется слишком много времени для реализации и выходит за рамки этого вопроса. Однако, если у вас открыто два окна (Main и Child), и вы закрываете Main, ребенок будет переведен в основную часть.Забастовкa >
По большей части вы должны иметь возможность получить общее представление о том, что происходит, и использовать его для своей собственной реализации.
Посмотрите все это в действии:
http://jsbin.com/mipanuro/1/edit
О да, чтобы увидеть его в действии... Откройте ссылку в нескольких окнах.:)
Обновление:
Я внес необходимые изменения, чтобы локальное хранилище поддерживало "основное" окно. Когда вы закрываете вкладки, дочерние окна затем могут быть переведены в главное окно. Существует два способа управления "основным" состоянием окна через параметр, переданный конструктору WindowStateManager. Эта реализация намного приятнее моей предыдущей попытки.
JavaScript:
// noprotect
var statusWindow = document.getElementById('status');
(function (win)
{
//Private variables
var _LOCALSTORAGE_KEY = 'WINDOW_VALIDATION';
var RECHECK_WINDOW_DELAY_MS = 100;
var _initialized = false;
var _isMainWindow = false;
var _unloaded = false;
var _windowArray;
var _windowId;
var _isNewWindowPromotedToMain = false;
var _onWindowUpdated;
function WindowStateManager(isNewWindowPromotedToMain, onWindowUpdated)
{
//this.resetWindows();
_onWindowUpdated = onWindowUpdated;
_isNewWindowPromotedToMain = isNewWindowPromotedToMain;
_windowId = Date.now().toString();
bindUnload();
determineWindowState.call(this);
_initialized = true;
_onWindowUpdated.call(this);
}
//Determine the state of the window
//If its a main or child window
function determineWindowState()
{
var self = this;
var _previousState = _isMainWindow;
_windowArray = localStorage.getItem(_LOCALSTORAGE_KEY);
if (_windowArray === null || _windowArray === "NaN")
{
_windowArray = [];
}
else
{
_windowArray = JSON.parse(_windowArray);
}
if (_initialized)
{
//Determine if this window should be promoted
if (_windowArray.length <= 1 ||
(_isNewWindowPromotedToMain ? _windowArray[_windowArray.length - 1] : _windowArray[0]) === _windowId)
{
_isMainWindow = true;
}
else
{
_isMainWindow = false;
}
}
else
{
if (_windowArray.length === 0)
{
_isMainWindow = true;
_windowArray[0] = _windowId;
localStorage.setItem(_LOCALSTORAGE_KEY, JSON.stringify(_windowArray));
}
else
{
_isMainWindow = false;
_windowArray.push(_windowId);
localStorage.setItem(_LOCALSTORAGE_KEY, JSON.stringify(_windowArray));
}
}
//If the window state has been updated invoke callback
if (_previousState !== _isMainWindow)
{
_onWindowUpdated.call(this);
}
//Perform a recheck of the window on a delay
setTimeout(function()
{
determineWindowState.call(self);
}, RECHECK_WINDOW_DELAY_MS);
}
//Remove the window from the global count
function removeWindow()
{
var __windowArray = JSON.parse(localStorage.getItem(_LOCALSTORAGE_KEY));
for (var i = 0, length = __windowArray.length; i < length; i++)
{
if (__windowArray[i] === _windowId)
{
__windowArray.splice(i, 1);
break;
}
}
//Update the local storage with the new array
localStorage.setItem(_LOCALSTORAGE_KEY, JSON.stringify(__windowArray));
}
//Bind unloading events
function bindUnload()
{
win.addEventListener('beforeunload', function ()
{
if (!_unloaded)
{
removeWindow();
}
});
win.addEventListener('unload', function ()
{
if (!_unloaded)
{
removeWindow();
}
});
}
WindowStateManager.prototype.isMainWindow = function ()
{
return _isMainWindow;
};
WindowStateManager.prototype.resetWindows = function ()
{
localStorage.removeItem(_LOCALSTORAGE_KEY);
};
win.WindowStateManager = WindowStateManager;
})(window);
var WindowStateManager = new WindowStateManager(false, windowUpdated);
function windowUpdated()
{
//"this" is a reference to the WindowStateManager
statusWindow.className = (this.isMainWindow() ? 'main' : 'child');
}
//Resets the count in case something goes wrong in code
//WindowStateManager.resetWindows()
HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div id='status'>
<span class='mainWindow'>Main Window</span>
<span class='childWindow'>Child Window</span>
</div>
</body>
</html>
CSS
#status
{
display:table;
width:100%;
height:500px;
border:1px solid black;
}
span
{
vertical-align:middle;
text-align:center;
margin:0 auto;
font-size:50px;
font-family:arial;
color:#ba3fa3;
display:none;
}
#status.main .mainWindow,
#status.child .childWindow
{
display:table-cell;
}
.mainWindow
{
background-color:#22d86e;
}
.childWindow
{
background-color:#70aeff;
}
Ответ 2
Более короткая версия с localStorage
и слушателем Storage
<script type="text/javascript">
// Broad cast that your're opening a page.
localStorage.openpages = Date.now();
var onLocalStorageEvent = function(e){
if(e.key == "openpages"){
// Listen if anybody else opening the same page!
localStorage.page_available = Date.now();
}
if(e.key == "page_available"){
alert("One more page already open");
}
};
window.addEventListener('storage', onLocalStorageEvent, false);
</script>
Обновление:
- Работает и при падении страницы.
- Стимулируйте падение страницы в Chrome:
chrome://inducebrowsercrashforrealz
Live демо
Ответ 3
Я знаю, что уже поздно, но, возможно, помогу кому-нибудь
Этот фрагмент кода определит, сколько открытых вкладок и сколько активных (видимых), и если ни одна из вкладок не активна, он выберет последнюю открытую вкладку как активную.
Этот код также будет обрабатывать сбой окон/вкладок и обновлять счет при сбое.
Поскольку localStorage в настоящее время не поддерживается в Stakoverflow, проверьте здесь.
<html>
<body>
Open in several tabs or windows
<div id="holder_element"></div>
<script type="text/javascript">
//localStorage.clear();
manage_crash();
//Create a windows ID for each windows that is oppened
var current_window_id = Date.now() + "";//convert to string
var time_period = 3000;//ms
//Check to see if PageVisibility API is supported or not
var PV_API = page_visibility_API_check();
/************************
** PAGE VISIBILITY API **
*************************/
function page_visibility_API_check ()
{
var page_visibility_API = false;
var visibility_change_handler = false;
if ('hidden' in document)
{
page_visibility_API = 'hidden';
visibility_change_handler = 'visibilitychange';
}
else
{
var prefixes = ['webkit','moz','ms','o'];
//loop over all the known prefixes
for (var i = 0; i < prefixes.length; i++){
if ((prefixes[i] + 'Hidden') in document)
{
page_visibility_API = prefixes[i] + 'Hidden';
visibility_change_handler = prefixes[i] + 'visibilitychange';
}
}
}
if (!page_visibility_API)
{
//PageVisibility API is not supported in this device
return page_visibility_API;
}
return {"hidden": page_visibility_API, "handler": visibility_change_handler};
}
if (PV_API)
{
document.addEventListener(PV_API.handler, function(){
//console.log("current_window_id", current_window_id, "document[PV_API.hidden]", document[PV_API.hidden]);
if (document[PV_API.hidden])
{
//windows is hidden now
remove_from_active_windows(current_window_id);
//skip_once = true;
}
else
{
//windows is visible now
//add_to_active_windows(current_window_id);
//skip_once = false;
check_current_window_status ();
}
}, false);
}
/********************************************
** ADD CURRENT WINDOW TO main_windows LIST **
*********************************************/
add_to_main_windows_list(current_window_id);
//update active_window to current window
localStorage.active_window = current_window_id;
/**************************************************************************
** REMOVE CURRENT WINDOWS FROM THE main_windows LIST ON CLOSE OR REFRESH **
***************************************************************************/
window.addEventListener('beforeunload', function ()
{
remove_from_main_windows_list(current_window_id);
});
/*****************************
** ADD TO main_windows LIST **
******************************/
function add_to_main_windows_list(window_id)
{
var temp_main_windows_list = get_main_windows_list();
var index = temp_main_windows_list.indexOf(window_id);
if (index < 0)
{
//this windows is not in the list currently
temp_main_windows_list.push(window_id);
}
localStorage.main_windows = temp_main_windows_list.join(",");
return temp_main_windows_list;
}
/**************************
** GET main_windows LIST **
***************************/
function get_main_windows_list()
{
var temp_main_windows_list = [];
if (localStorage.main_windows)
{
temp_main_windows_list = (localStorage.main_windows).split(",");
}
return temp_main_windows_list;
}
/**********************************************
** REMOVE WINDOWS FROM THE main_windows LIST **
***********************************************/
function remove_from_main_windows_list(window_id)
{
var temp_main_windows_list = [];
if (localStorage.main_windows)
{
temp_main_windows_list = (localStorage.main_windows).split(",");
}
var index = temp_main_windows_list.indexOf(window_id);
if (index > -1) {
temp_main_windows_list.splice(index, 1);
}
localStorage.main_windows = temp_main_windows_list.join(",");
//remove from active windows too
remove_from_active_windows(window_id);
return temp_main_windows_list;
}
/**************************
** GET active_windows LIST **
***************************/
function get_active_windows_list()
{
var temp_active_windows_list = [];
if (localStorage.actived_windows)
{
temp_active_windows_list = (localStorage.actived_windows).split(",");
}
return temp_active_windows_list;
}
/*************************************
** REMOVE FROM actived_windows LIST **
**************************************/
function remove_from_active_windows(window_id)
{
var temp_active_windows_list = get_active_windows_list();
var index = temp_active_windows_list.indexOf(window_id);
if (index > -1) {
temp_active_windows_list.splice(index, 1);
}
localStorage.actived_windows = temp_active_windows_list.join(",");
return temp_active_windows_list;
}
/********************************
** ADD TO actived_windows LIST **
*********************************/
function add_to_active_windows(window_id)
{
var temp_active_windows_list = get_active_windows_list();
var index = temp_active_windows_list.indexOf(window_id);
if (index < 0)
{
//this windows is not in active list currently
temp_active_windows_list.push(window_id);
}
localStorage.actived_windows = temp_active_windows_list.join(",");
return temp_active_windows_list;
}
/*****************
** MANAGE CRASH **
******************/
//If the last update didn't happened recently (more than time_period*2)
//we will clear saved localStorage data and reload the page
function manage_crash()
{
if (localStorage.last_update)
{
if (parseInt(localStorage.last_update) + (time_period * 2) < Date.now())
{
//seems a crash came! who knows!?
//localStorage.clear();
localStorage.removeItem('main_windows');
localStorage.removeItem('actived_windows');
localStorage.removeItem('active_window');
localStorage.removeItem('last_update');
location.reload();
}
}
}
/********************************
** CHECK CURRENT WINDOW STATUS **
*********************************/
function check_current_window_status(test)
{
manage_crash();
if (PV_API)
{
var active_status = "Inactive";
var windows_list = get_main_windows_list();
var active_windows_list = get_active_windows_list();
if (windows_list.indexOf(localStorage.active_window) < 0)
{
//last actived windows is not alive anymore!
//remove_from_main_windows_list(localStorage.active_window);
//set the last added window, as active_window
localStorage.active_window = windows_list[windows_list.length - 1];
}
if (! document[PV_API.hidden])
{
//Window page is visible
localStorage.active_window = current_window_id;
}
if (localStorage.active_window == current_window_id)
{
active_status = "Active";
}
if (active_status == "Active")
{
active_windows_list = add_to_active_windows(current_window_id);
}
else
{
active_windows_list = remove_from_active_windows(current_window_id);
}
console.log(test, active_windows_list);
var element_holder = document.getElementById("holder_element");
element_holder.insertAdjacentHTML("afterbegin", "<div>"+element_holder.childElementCount+") Current Windows is "+ active_status +" "+active_windows_list.length+" window(s) is visible and active of "+ windows_list.length +" windows</div>");
}
else
{
console.log("PageVisibility API is not supported :(");
//our INACTIVE pages, will remain INACTIVE forever, you need to make some action in this case!
}
localStorage.last_update = Date.now();
}
//check storage continuously
setInterval(function(){
check_current_window_status ();
}, time_period);
//initial check
check_current_window_status ();
</script>
</body>
</html>