Axe*_*rks 20 javascript iphone mobile-safari dom-events ios
如何构建一个能够监控页面何时获得焦点的网页,尤其是当Safari处于后台并且用户将Safari切换回前台时.
在iPhone上切换到Safari时,下面的代码不会触发事件
<html>
<head>
<script type="text/javascript">
window.onfocus = function() { alert("onfocus"); };
</script>
</head>
<body>
Main text
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
根据http://www.quirksmode.org/dom/events/index.html:Windows iPhone在窗口获得焦点时不会触发事件.
所以我的问题仍然是:如何通过在Safari for iPhone中的网页上使用javascript来检测窗口是否获得焦点?
Dav*_*eck 15
我相信当应用程序进入后台时,计时器(setInterval())会被暂停.你可以这样做:
var lastFired = new Date().getTime();
setInterval(function() {
now = new Date().getTime();
if(now - lastFired > 5000) {//if it's been more than 5 seconds
alert("onfocus");
}
lastFired = now;
}, 500);
Run Code Online (Sandbox Code Playgroud)
您可能需要调整这些时间间隔以满足您的需求.
但是,最有可能的是,如果它足够长,需要刷新(几天),safari可能会重新加载页面,因为它是内存不足.
根据您需要支持的内容,您需要各种不同的技术来检测页面何时可见.由于浏览器供应商,浏览器版本,操作系统,在WebView/UIWebView/WKWebView中运行等而发生变化.
您可以使用此页面查看正在发生的事件.我发现要检测页面"唤醒"所有组合时我需要注册所有以下事件:
我曾经也使用过webkitRequestAnimationFrame,但是我删除了它,因为它可能导致jank(AFAIK渲染引擎对它的主线程执行阻塞调用).
要尝试的事情:
您可以看到发生了哪些事件:
iOS:请注意,如果使用计时器来检测iOS UIWebView是否已进入睡眠状态,则需要使用new Date.getNow()
和不使用来测量差异performance.now()
.这是因为performance.now()
当页面进入睡眠状态时停止计算时间,iOS也很难实现性能.现在()...(旁白:你可以通过检测页面的差异来测量页面睡眠的时间长度.对于差异new Date.getNow()
和performance.now()
,认准!=上测试页).
如果您正在使用UIWebView,那么有两种技术可行(如果您支持iOS7应用程序,则必须使用UIWebView).WKWebView具有visibilitychange事件,因此不需要变通方法.
==技术1.
当appWillEnterForeground事件发生在app中时,调用UIWebView stringByEvaluatingJavaScriptFromString来调用你的JavaScript pageAwakened().
好处:干净,准确.
缺点:需要Objective-C代码.被调用的函数需要可从全局范围访问.
==技术2.
使用webkitRequestAnimationFrame并检测时间延迟.
好处:仅限JavaScript.适用于iOS7上的移动Safari.
缺点:丑陋的风险和使用webkitRequestAnimationFrame是一个严重的黑客攻击.
// iOS specific workaround to detect if Mobile App comes back to focus. UIWebView and old iOS don't fire any of: window.onvisibilitychange, window.onfocus, window.onpageshow
function iosWakeDetect() {
function requestAnimationFrameCallback() {
webkitRequestAnimationFrame(function() {
// Can't use timestamp from webkitRequestAnimationFrame callback, because timestamp is not incremented while app is in background. Instead use UTC time. Also can't use performance.now() for same reason.
var thisTime = (new Date).getTime();
if (lastTime && (thisTime - lastTime) > 60000) { // one minute
// Very important not to hold up browser within webkitRequestAnimationFrame() or reference any DOM - zero timeout so shoved into event queue
setTimeout(pageAwakened, 0);
}
lastTime = thisTime;
requestAnimationFrameCallback();
});
}
var lastTime;
if (/^iPhone|^iPad|^iPod/.test(navigator.platform) && !window.indexedDB && window.webkitRequestAnimationFrame) { // indexedDB sniff: it is missing in UIWebView
requestAnimationFrameCallback();
}
}
function pageAwakened() {
// add code here to remove duplicate events. Check !document.hidden if supported
};
window.addEventListener('focus', pageAwakened);
window.addEventListener('pageshow', pageAwakened);
window.addEventListener('visibilitychange', function() {
!document.hidden && pageAwakened();
});
Run Code Online (Sandbox Code Playgroud)
我写了一个小测试页面来查看哪些事件被发送到 iOS 上的窗口。
该页面具有“Apple Web 应用程序功能”,因此您可以将其保存到主屏幕并在独立模式下进行测试。
这是页面:窗口事件的测试
编码:
// determine if this is a touch-capable device
const isTouchDevice = ('ontouchstart' in window) ||
(navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0);
console.log(`isTouchDevice: ${isTouchDevice ? 'TRUE' : 'FALSE'} `);
const button = document.getElementById('btnClear');
const divEvents = document.getElementById('divEvents');
const olEvents = document.getElementById('olEvents');
const divBottom = document.getElementById('divBottom');
// handle "clear history" button click
button.addEventListener('click', function() {
if (isTouchDevice) {
// simulate click on button using `focus` and `blur`
button.focus();
setTimeout(() => button.blur(), 500);
}
olEvents.innerHTML = '';
});
const eventNames = [
'load',
'focus',
'blur',
'change',
'close',
'error',
'haschange',
'message',
'offline',
'online',
'pagehide',
'pageshow',
'popstate',
'resize',
'submit',
'unload',
'beforeunload'
];
eventNames.forEach(function(eventName) {
window.addEventListener(eventName, function(evt) {
const now = new Date();
const timeStr = now.getHours().toString().padStart(2, '0') + ':' +
now.getMinutes().toString().padStart(2, '0') + ':' +
now.getSeconds().toString().padStart(2, '0') + '.' +
now.getMilliseconds();
let li = document.createElement('li');
li.innerHTML = timeStr + ' - ' + `<code>${evt.type}</code>`;
olEvents.appendChild(li);
// scroll to bottom
// window.scrollTo(0, divBottom.offsetTop);
const bottomOffset = divBottom.offsetTop;
divEvents.scrollTop = bottomOffset - 10;
});
});
Run Code Online (Sandbox Code Playgroud)
#divEvents {
border: 1px solid rgba(0, 0, 0, 0.5);
height: 400px;
max-width: 60rem;
padding: 1rem 0;
overflow-y: auto;
}
#olEvents {
font-size: 87.5%;
}
#divBottom {
height: 0px;
}
code {
font-size: 100%;
}
/* handle the sticky hover problem on touch devices */
@media (hover:none) {
/* set button hover style to match non-hover */
.btn-outline-primary:hover {
color: #007bff;
background-color: transparent;
background-image: none;
border-color: #007bff;
}
/* set button focus style to match hover */
.btn-outline-primary:focus {
color: #fff;
background-color: #007bff;
border-color: #007bff;
}
}
Run Code Online (Sandbox Code Playgroud)
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, maximum-scale=1, minimum-scale=1, shrink-to-fit=no, user-scalable=no">
<!-- apple web app meta tags -->
<meta name="apple-mobile-web-app-title" content="WinEvents">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<title>Test of Window Events</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootsdark@latest/dist/bootsdark.min.css">
</head>
<body class="d-flex flex-column h-100">
<header>
<!-- Fixed navbar -->
<nav class="navbar navbar-expand-md navbar-dark bg-dark">
<a class="navbar-brand" href="https://terrymorse.com">Terry Morse
Software</a>
</nav>
</header>
<main role="main" class="flex-shrink-0 m-4">
<h1>Test of Window Events</h1>
<p>Displays all of the events (except for
<code>scroll</code>) sent to <code>document.window</code>.</p>
<p>
<button id="btnClear" class="btn btn-sm btn-outline-primary"
>Clear History</button>
</p>
<h4>Events Caught:</h4>
<div id="divEvents">
<ol id="olEvents" class="text-monospace"></ol>
<div id="divBottom"></div>
</div>
</main>
</body>
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
17787 次 |
最近记录: |