🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
[TOC] ## Web Workders Web Worker为Web内容在后台线程中运行脚本提供了一种简单的方法。线程可以执行任务而不干扰用户界面。此外,他们可以使用XMLHttpRequest执行 I/O \(尽管responseXML和通道属性总是为空\)。一旦创建, 一个worker 可以将消息发送到创建它的JavaScript代码, 通过将消息发布到该代码指定的事件处理程序 \(反之亦然\)。 ### API 一个worker是使用一个构造函数创建的一个对象\(e.g.[`Worker()`](https://developer.mozilla.org/zh-CN/docs/Web/API/Worker/Worker)\) 运行一个命名的JavaScript文件 - 这个文件包含将在工作线程中运行的代码; workers 运行在另一个全局上下文中,不同于当前的[`window`](https://developer.mozilla.org/zh-CN/docs/Web/API/Window)。 因此,使用[`window`](https://developer.mozilla.org/zh-CN/docs/Web/API/Window)快捷方式获取当前全局的范围 \(而不是[`self`](https://developer.mozilla.org/zh-CN/docs/Web/API/Window/self)\) 在一个[`Worker`](https://developer.mozilla.org/zh-CN/docs/Web/API/Worker)内将返回错误。 在专用workers的情况下,[`DedicatedWorkerGlobalScope`](https://developer.mozilla.org/zh-CN/docs/Web/API/DedicatedWorkerGlobalScope)对象代表了worker的上下文(专用workers是指标准worker仅在单一脚本中被使用;共享worker的上下文是[`SharedWorkerGlobalScope`](https://developer.mozilla.org/zh-CN/docs/Web/API/SharedWorkerGlobalScope)对象)。一个专用worker仅仅能被首次生成它的脚本使用,而共享worker可以同时被多个脚本使用。 > 参照 [The Web Workers API landing page](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API)获取workers的参考文档和更多指引。 在worker线程中你可以运行任何你喜欢的代码,不过有一些例外情况。比如:在worker内直接操作DOM节点,或者使用[`window`](https://developer.mozilla.org/zh-CN/docs/Web/API/Window)对象的默认方法和属性。然而你可以使用大量window对象之下的东西,包括WebSockets,IndexedDB以及FireFox OS专用的Data Store API等数据存储机制。查看[Functions and classes available to workers](https://developer.mozilla.org/en-US/docs/Web/API/Worker/Functions_and_classes_available_to_workers)获取详情。 workers和主线程间的数据传递通过这样的消息机制进行——双方都使用postMessage\(\)方法发送各自的消息,使用onmessage事件处理函数来响应消息(消息被包含在[`Message`](https://developer.mozilla.org/zh-CN/docs/Web/Reference/Events/Message)事件的data属性中)。这个过程中数据并不是被共享而是被复制。 只要运行在同源的父页面中,workers可以依次生成新的workers;并且可以使用[`XMLHttpRequest`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) 进行网络I/O,responseXML和XMLHttpRequest的通道属性一直返回null的情况除外。 ### Worker 的使用场景 * 执行一些大计算量的操作 * 异步加载资源 ### **适用于 Worker 的功能** 由于 Web Worker 的多线程行为,所以它们只能使用 JavaScript 功能的子集: * navigator 对象 * location 对象(只读) * XMLHttpRequest * setTimeout\(\)/clearTimeout\(\) 和 setInterval\(\)/clearInterval\(\) * 应用缓存 * 使用 importScripts\(\) 方法导入外部脚本 * 生成其他 Web Worker Worker 无法使用: * DOM(非线程安全) * window 对象 * document 对象 * parent 对象 ### 专用Workder #### worker特性检测 ``` //main.js if (window.Worker) { ... } ``` #### 生成一个专用worker 调用[`Worker()`](https://developer.mozilla.org/zh-CN/docs/Web/API/Worker/Worker)的构造器,指定一个脚本的URI来执行worker线程(main.js): ``` //main.js var myWorker = new Worker('worker.js'); ``` #### 专用worker中消息的接收和发送 向一个worker发送消息: ``` //main.js first.onchange = function() { myWorker.postMessage([first.value,second.value]); console.log('Message posted to worker'); } second.onchange = function() { myWorker.postMessage([first.value,second.value]); console.log('Message posted to worker'); } ``` 变量first和second代表2个`<input>`元素;它们当中任意一个的值发生改变时,myWorker.postMessage\(\[first.value,second.value\]\)会将这2个值组成数组发送给worker。 在worker中接收到消息后,我们可以写这样一个事件处理函数代码作为响应: ``` //worker.js onmessage = function(e) { console.log('Message received from main script'); var workerResult = 'Result: ' + (e.data[0] * e.data[1]); console.log('Posting message back to main script'); postMessage(workerResult); } ``` onmessage处理函数允许我们在任何时刻,一旦接收到消息就可以执行一些代码,代码中消息本身作为事件的data属性进行使用。这里我们简单的对这2个数字作乘法处理并再次使用postMessage\(\)方法,将结果回传给主线程。 回到主线程,我们再次使用onmessage以响应worker回传的消息: ``` myWorker.onmessage = function(e) { result.textContent = e.data; console.log('Message received from worker'); } ``` > 作为参数传递给worker构造器的URI必须遵循[同源策略](https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy)。 > > 在主线程中使用时,`onmessage`和`postMessage()`必须挂在worker对象上,而在worker中使用时不用这样做。原因是,在worker内部,worker是有效的全局作用域。 > > 当一个消息在主线程和worker之间传递时,它被复制或者转移了,而不是共享。 #### 终止worker {#终止worker} 如果你需要从主线程中立刻终止一个运行中的worker,可以调用worker的[`terminate`](https://developer.mozilla.org/zh-CN/docs/Web/API/Worker)方法: ``` myWorker.terminate(); ``` worker 线程会被立即杀死,不会有任何机会让它完成自己的操作或清理工作。 而在worker线程中,workers 也可以调用自己的 [`close`](https://developer.mozilla.org/zh-CN/docs/Web/API/WorkerGlobalScope) 方法进行关闭: ``` close(); ``` #### 处理错误 当 worker 出现运行中错误时,它的 `onerror` 事件处理函数会被调用。它会收到一个扩展了 `ErrorEvent` 接口的名为`error`的事件。 该事件不会冒泡并且可以被取消;为了防止触发默认动作,worker 可以调用错误事件的 [`preventDefault()`](https://developer.mozilla.org/en/DOM/event.preventDefault)`方法。` 错误事件有以下三个用户关心的字段: `message`可读性良好的错误消息。 `filename`发生错误的脚本文件名。 `lineno`发生错误时所在脚本文件的行号。 #### 生成subworker 如果需要的话 worker 能够生成更多的 worker。这就是所谓的subworker,它们必须托管在同源的父页面内。而且,subworker 解析 URI 时会相对于父 worker 的地址而不是自身页面的地址。这使得 worker 更容易记录它们之间的依赖关系。 #### 引入脚本与库 Worker 线程能够访问一个全局函数`importScripts()`来引入脚本,该函数接受0个或者多个URI作为参数来引入资源;以下例子都是合法的: ``` importScripts(); /* 什么都不引入 */ importScripts('foo.js'); /* 只引入 "foo.js" */ importScripts('foo.js', 'bar.js'); /* 引入两个脚本 */ ``` 浏览器加载并运行每一个列出的脚本。每个脚本中的全局对象都能够被 worker 使用。如果脚本无法加载,将抛出 `NETWORK_ERROR` 异常,接下来的代码也无法执行。而之前执行的代码\(包括使用[`window.setTimeout()`](https://developer.mozilla.org/zh-CN/docs/Web/API/Window/setTimeout)异步执行的代码\)依然能够运行。`importScripts()`**之后**的函数声明依然会被保留,因为它们始终会在其他代码之前运行。 > 脚本的下载顺序不固定,但执行时会按照传入 `importScripts()`中的文件名顺序进行。这个过程是同步完成的;直到所有脚本都下载并运行完毕, `importScripts()`才会返回。 ### 共享worker 一个共享worker可以被多个脚本使用——即使这些脚本正在被不同的window、iframe或者worker访问。这一部分,我们会讨论[共享worker基础示例](https://github.com/mdn/simple-shared-worker)([运行共享worker](https://mdn.github.io/simple-shared-worker/))中的javascript代码:该示例与专用worker基础示例非常相像,只是有2个可用函数被存放在不同脚本文件中:两数相乘函数,以及求平方函数。这两个脚本用同一个worker来完成实际需要的运算。 #### 生成一个共享worker ``` var myWorker = new SharedWorker('worker.js'); ``` 专用worker与共享worker一个非常大的区别在于,与一个共享worker通信必须通过端口对象——一个确切的打开的端口供脚本与worker通信(在专用worker中这一部分是隐式进行的)。 在传递消息之前,端口连接必须被显式的打开,打开方式是使用onmessage事件处理函数或者start\(\)方法。尽管示例中的 [multiply.js](https://github.com/mdn/simple-shared-worker/blob/gh-pages/multiply.js) 和 [worker.js](https://github.com/mdn/simple-shared-worker/blob/gh-pages/worker.js) 文件调用了start\(\)方法,这些调用并不那么重要因为onmessage事件处理函数正在被使用。start\(\)方法的调用只在一种情况下需要,那就是消息事件被addEventListener\(\)方法使用。 在传递消息之前,端口连接必须被显式的打开,打开方式是使用onmessage事件处理函数或者start\(\)方法。尽管示例中的 [multiply.js](https://github.com/mdn/simple-shared-worker/blob/gh-pages/multiply.js) 和 [worker.js](https://github.com/mdn/simple-shared-worker/blob/gh-pages/worker.js) 文件调用了start\(\)方法,这些调用并不那么重要因为onmessage事件处理函数正在被使用。start\(\)方法的调用只在一种情况下需要,那就是消息事件被addEventListener\(\)方法使用。 在使用start\(\)方法打开端口连接时,如果父级线程和worker线程需要双向通信,那么它们都需要调用start\(\)方法。 ``` myWorker.port.start(); // 父级线程中的调用 ``` ``` port.start(); // worker线程中的调用, 假设port变量代表一个端口 ``` ## History ### 穿越历史 使用back(),forward()和go()方法完成用户历史记录的前后移动。 ### 前进和后退 要回溯历史,只要做到: ``` window.history.back(); ``` 这与用户点击浏览器工具栏上的“后退”按钮完全相同。 同样,你可以向前移动(就像用户点击了Forward按钮),如下所示: ``` window.history.forward(); ``` ### 转向历史上的特定时刻 您可以使用go()方法从会话历史记录中加载特定的页面,通过它相对于当前页面的位置来标识(当前页面当然是相对索引0)。 向后移动一页(相当于回调()): ``` window.history.go(-1); ``` 向前移动页面,就像调用forward()一样: ``` window.history.go(1); ``` 同样,您可以通过传递2来前进2页,依此类推。 您可以通过查看length属性的值来确定历史堆栈中的页数: ``` var numberOfEntries = window.history.length; ``` > Internet Explorer支持将字符串URL作为参数传递给();这是非标准的,不被Gecko支持。 ### 添加和修改历史条目 HTML5引入了history.pushState()和history.replaceState()方法,可以分别添加和修改历史条目。这些方法与window.onpopstate事件一起工作。 使用history.pushState()更改在更改状态后创建的XMLHttpRequest对象的HTTP标头中使用的引用链接。引用者将是在创建XMLHttpRequest对象时窗口是这个文档的URL。 #### pushState()方法的例子 假设[http://mozilla.org/foo.html执行以下JavaScript:](http://mozilla.org/foo.html执行以下JavaScript:) `var stateObj = {foo:“bar”};` `history.pushState(stateObj,“page 2”,“bar.html”);` 这将导致URL栏显示[http://mozilla.org/bar.html,但不会导致浏览器加载bar.html甚至检查bar.html是否存在。](http://mozilla.org/bar.html,但不会导致浏览器加载bar.html甚至检查bar.html是否存在。) 现在假设用户现在导航到[http://google.com,然后点击返回。此时,URL栏会显示http://mozilla.org/bar.html,页面将会得到一个状态对象包含stateObj副本的popstate事件。页面本身看起来像foo.html,虽然页面可能会在popstate事件中修改它的内容。](http://google.com,然后点击返回。此时,URL栏会显示http://mozilla.org/bar.html,页面将会得到一个状态对象包含stateObj副本的popstate事件。页面本身看起来像foo.html,虽然页面可能会在popstate事件中修改它的内容。) 如果我们再次点击,URL将变为[http://mozilla.org/foo.html,文档将会得到另一个popstate事件,这次是一个null状态对象。在这里,返回不会改变文档内容与上一步的内容,尽管文档可能会在接收到popstate事件后手动更新其内容。](http://mozilla.org/foo.html,文档将会得到另一个popstate事件,这次是一个null状态对象。在这里,返回不会改变文档内容与上一步的内容,尽管文档可能会在接收到popstate事件后手动更新其内容。) pushState()方法 pushState()有三个参数:一个状态对象,一个标题(当前被忽略)和(可选)一个URL。让我们来更详细地检查这三个参数中的每一个: * 状态对象 - 状态对象是与由pushState()创建的新历史记录条目相关联的JavaScript对象。每当用户导航到新状态时,将触发一个popstate事件,并且该事件的state属性包含历史记录条目状态对象的副本。 状态对象可以是任何可以序列化的东西。由于Firefox会将状态对象保存到用户的磁盘中,以便在用户重新启动浏览器之后可以恢复它们,所以我们在状态对象的序列化表示上强加了一个640k字符的大小限制。如果你传递了一个状态对象的序列化表示大于这个pushState(),该方法将抛出一个异常。如果您需要更多的空间,建议您使用sessionStorage和/或localStorage。 * 标题 - Firefox目前忽略这个参数,虽然它可能在将来使用它。在这里传递空字符串应该对将来对方法的更改是安全的。或者,您可以传递您正在移动的状态的简短标题。 * URL - 新的历史记录的URL由此参数给出。请注意,在调用pushState()之后,浏览器将不会尝试加载此URL,但可能会在稍后尝试加载URL,例如在用户重新启动浏览器之后。新的URL不需要是绝对的;如果它是相对的,则相对于当前URL解析。新的网址必须与当前网址的来源相同;否则,pushState()会抛出异常。该参数是可选的;如果未指定,则将其设置为文档的当前URL。 从某种意义上说,调用pushState()类似于设置window.location =“\#foo”,因为两者都将创建并激活与当前文档相关联的另一个历史记录条目。但是pushState()有一些优点: * 新的URL可以是与当前URL相同的任何URL。相比之下,只有修改hash值时,设置window.location才能使您保持在同一个文档中。 * 如果您不想更改网址,则不必更改网址。相反,设置window.location =“\#foo”;如果当前hash不是\#foo,则只创建一个新的历史记录条目。 * 您可以将任意数据与新的历史记录条目相关联。使用基于hash的方法,您需要将所有相关数据编码成一个简短的字符串。 * 如果标题随后被浏览器使用,则可以使用该数据(独立于hash)。 > pushState()永远不会引发hashchange事件,即使新的URL仅在其哈希中与旧的URL不同。 #### replaceState()方法 history.replaceState()的运行方式与history.pushState()完全相同,只是replaceState()修改了当前的历史记录,而不是创建一个新的历史记录。请注意,这并不妨碍在全局浏览器历史记录中创建新条目。 当您想要更新当前历史记录条目的状态对象或URL以响应某些用户操作时,replaceState()特别有用。 ## ContentEditable 只要将HTML元素的[`contenteditable`](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Global_attributes#attr-contenteditable)属性值设置`true`, 就可以激活编辑模式,那么该元素范围中的内容都是可编辑的. ``` <div contenteditable="true"> This text can be edited by the user. </div> ``` ## 拖放 ## 焦点管理 在 HTML5 工作草案中,DOM 属性 [`activeElement`](https://developer.mozilla.org/cn/DOM/document.activeElement)与方法 [`hasFocus()`](https://developer.mozilla.org/cn/DOM/document.hasFocus)为程序员提供了更好的控制页面交互的能力,特别是对于用户行为引发的交互。例如,它们都可以用于统计使用目的,跟踪页面特定链接的点击次数,计算元素获得焦点的次数等等。此外,当与 AJAX 技术结合以后,将会减少向服务器请求的数目,这取决于用户的活跃程度和页面的布局。 ### document.hasFocus `Document.hasFocus()`方法返回一个[`Boolean`](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Boolean),表明当前文档或者当前文档内的节点是否获得了焦点。该方法可以用来判断当前文档中的活动元素是否获得了焦点。 > 当查看一个文档时,当前文档中获得焦点的元素一定是当前文档的活动元素,但一个文档中的活动元素不一定获得了焦点.。例如, 一个在后台的窗口中的活动元素一定没有获得焦点。 #### 语法 ``` focused = document.hasFocus(); ``` **返回值** 如果当前文档的活动元素获得了焦点,返回`true`,否则返回false。 ## Web-based protocol handlers ### 背景 利用非http协议,从网页链接到一些别的资源,这种做法是相当普遍的。比如 `mailto:` 协议: ``` <a href="mailto:webmaster@example.com">Web Master</a> ``` 当Web页面作者想直接从网页上,为用户提供一个方便的方式发送一个电子邮件,时可以使用mailto:链接。激活链接时,浏览器应该启动默认的桌面应用程序来处理电子邮件。你可以认为这是一个_基于桌面的_协议处理器。 基于网络的协议处理程序也允许基于web的应用程序参与这一过程。随着越来越多的类型的应用程序迁移到web,这变得越来越重要。事实上,有许多基于web的电子邮件处理的应用程序可以处理一个mailto链接。 ### 注册 设置一个web应用程序作为一个协议处理器不是一个很麻烦的过程。web应用程序可以使用[registerProtocolHandler\(\)](https://developer.mozilla.org/en-US/docs/Web/API/navigator.registerProtocolHandler)注册到浏览器上,从而对于一个给定的协议来讲,作为一个潜在的处理程序。例如: ``` navigator.registerProtocolHandler("mailto", "https://www.example.com/?uri=%s", "Example Mail"); ``` 参数为: * 协议名称. * url模板。%s用来替换链接的`href`属性,之后通过这个url来发起一个GET请求. * 一个对用户友好的协议处理器的名字. > 试图执行登记或注册时,当前网页必须与提供的URL模板在相同的域,否则将会失败。例如,[http://example.com/homepage.html可以为\`http://example.com/handle\_mailto/%s\`注册一个协议处理程序](http://example.com/homepage.html可以为`http://example.com/handle_mailto/%s`注册一个协议处理程序), 但`http://example.org/handle_mailto/%s不可以`. 多次注册相同的协议处理程序会弹出不同的通知,表明协议处理器已经注册。因此,发起一个注册协议处理程序的请求,之后检查是否注册是一个很好的方法。比如下面的例子。 #### 例子 ``` <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html lang="en"> <head> <title>Web Protocol Handler Sample - Register</title> <script type="text/javascript"> var url = "http://starkravingfinkle.org/projects/wph/handler.php?value=%s"; if (!navigator.isProtocolHandlerRegistered("fake", url)) { navigator.registerProtocolHandler("fake", url, "Fake Protocol"); } </script> </head> <body> <h1>Web Protocol Handler Sample</h1> <p>This web page will install a web protocol handler for the <code>fake:</code> protocol.</p> </body> </html> ``` ### 激活 现在,只要用户点击链接,使用注册协议,浏览器将跳转到web应用程序注册时提供的URL。Firefox在默认情况下,跳转前会提示用户操作。 ![](https://developer.mozilla.org/@api/deki/files/971/=Wph-launch.png "Image:wph-launch.png") #### Example ``` <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"> <html lang="en"> <head> <title>Web Protocol Handler Sample - Test</title> </head> <body> <p>Hey have you seen <a href="fake:this%20is%20fake">this</a> before?</p> </body> </html> ``` ### 处理 下一步是处理这个动作。浏览器在激活的链接中提取出href属性,之后与注册时提供的URL模板进行拼装,之后经由拼装好的URL发起一个HTTP GET请求.因此下面的例子中,浏览器会基于此URL发起一个GET请求: ``` http://starkravingfinkle.org/projects/wph/handler.php?value=fake:this%20is%20fake ``` 服务端代码可以提取查询字符串的参数,执行所需的操作。 > 服务端代码会接收到href的**全部**内容。这意味着服务端代码必须解析出数据中的协议。 ## window.requestAnimationFrame `window.requestAnimationFrame()` 方法告诉浏览器您希望执行动画并请求浏览器调用指定的函数在下一次重绘之前更新动画。该方法使用一个回调函数作为参数,这个回调函数会在浏览器重绘之前调用。 **注意:** 若您想要在下次重绘时产生另一个动画画面,您的回调例程必须调用`requestAnimationFrame()`。 当你准备好更新屏幕画面时你就应用此方法。这会要求你的动画函数在浏览器下次重绘前执行。回调的次数常是每秒60次,但大多数浏览器通常匹配 W3C 所建议的刷新率。如果网页于后台或隐藏在[`<iframe>`](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/iframe)里面,重绘频率可能会大大降低以提升性能和电池耐久度。 回调函数只会被传入一个参数,[`DOMHighResTimeStamp`](https://developer.mozilla.org/zh-CN/docs/Web/API/DOMHighResTimeStamp),指示当前被 requestAnimationFrame 序列化的函数队列被触发的时间。即使经过了许多对之前回调的计算工作时间,单个帧中的多个回调也都将被传入相同的时间戳。此数值是一个十进制数,单位毫秒,最小精度为1ms\(1000μs\)。 ### 语法 ``` window.requestAnimationFrame(callback); ``` #### 参数 `callback` 一个在每次需要重新绘制动画时调用的包含指定函数的参数。这个回调函数有一个传参,[`DOMHighResTimeStamp`](https://developer.mozilla.org/zh-CN/docs/Web/API/DOMHighResTimeStamp),指示从触发 requestAnimationFrame 回调到现在的时间(从[`performance.now()`](https://developer.mozilla.org/zh-CN/docs/Web/API/Performance/now)取得)。 #### 返回值 一个`long`整数,请求 ID ,也是回调列表中唯一的标识。这是一个非零值,但你恐怕也不能从其值中作出什么臆想。你可以传此值到[`window.cancelAnimationFrame()`](https://developer.mozilla.org/zh-CN/docs/Web/API/Window/cancelAnimationFrame)以取消回调函数。 ### 范例 ``` var start = null; var element = document.getElementById('SomeElementYouWantToAnimate'); element.style.position = 'absolute'; function step(timestamp) { if (!start) start = timestamp; var progress = timestamp - start; element.style.left = Math.min(progress / 10, 200) + 'px'; if (progress < 2000) { window.requestAnimationFrame(step); } } window.requestAnimationFrame(step); ``` ## Fullscreen API 全屏API为使用用户的整个屏幕呈现网页内容提供了一个简单的方法。 API可让您轻松地指导浏览器创建一个元素及其子元素(如果有的话)占据全屏,从而在屏幕上消除所有浏览器用户界面和其他应用程序。 > 目前并不是所有的浏览器都使用API的前缀版本。 请查阅总结前缀和名称差异的表格 ### 激活全屏模式 给定一个你想以全屏模式呈现的元素(例如&lt;video&gt;),你可以通过调用它的Element.requestFullscreen()方法以全屏模式呈现它。 ### 表现差异 Gecko和WebKit实现之间有一个关键的区别:Gecko自动将CSS规则添加到元素,扩展它以填充屏幕:“width:100%; height:100%”。 WebKit不会这样做; 相反,它将全屏幕元素以相同的大小居中在黑色的屏幕中。 要在WebKit中获得相同的全屏行为,您需要添加自己的“宽度:100%;高度:100%”。 CSS自己对元素进行规则: ``` #myvideo:-webkit-full-screen { width: 100%; height: 100%; } ``` 另一方面,如果您试图模拟WebKit在Gecko上的行为,则需要将要呈现的元素放置在另一个元素内,而不是使用全屏模式,并使用CSS规则调整内部元素以匹配 你想要的外观。 ### 注意 全屏模式成功使用时,包含该元素的文档将收到fullscreenchange事件。 当全屏模式退出时,文档再次收到fullscreenchange事件。 请注意,fullscreenchange事件本身不提供有关文档是进入还是退出全屏模式的任何信息,但是如果文档具有非空的fullscreenElement,则说明您处于全屏模式。 ### 全屏请求失败时 不能保证你能够切换到全屏模式。 例如,&lt;iframe&gt;元素具有allowfullscreen属性,以便选择允许其内容以全屏模式显示。 另外,某些类型的内容(如窗口化插件)无法以全屏模式显示。 试图放置一个无法以全屏模式显示的元素(或者这样的元素的父代或后代)将不起作用。 相反,请求全屏的元素将收到mozfullscreenerror事件。 当全屏请求失败时,Firefox会将错误消息记录到Web控制台,以解释请求失败的原因。 但是在Chrome和更新版本的Opera中,不会产生这样的警告。 > ### 全屏请求需要在事件处理程序中调用,否则将被拒绝。 ### 退出全屏模式 您可以通过调用Document.exitFullscreen()方法来退出全屏模式。 ### 其他信息 document提供了一些在开发全屏Web应用程序时可能有用的附加信息: [`fullscreenElement`](https://developer.mozilla.org/en-US/docs/Web/API/Document/fullscreenElement) > 当前全屏显示的元素。 如果不是null,则文档处于全屏模式。 如果为空,则文档不处于全屏模式。 [`fullscreenEnabled`](https://developer.mozilla.org/en-US/docs/Web/API/Document/fullscreenEnabled) > 文档当前是否处于允许请求全屏模式的状态。 ### 你的用户想知道的事情 您需要确保让用户知道他们可以按ESC键(或F11)退出全屏模式。 此外,在全屏模式下,导航到另一个页面,更改标签或切换到其他应用程序(例如,使用Alt-Tab)也会退出全屏模式。 ### 例子 ``` document.addEventListener("keydown", function(e) { if (e.keyCode == 13) { toggleFullScreen(); } }, false); function toggleFullScreen() { if (!document.fullscreenElement) { document.documentElement.requestFullscreen(); } else { if (document.exitFullscreen) { document.exitFullscreen(); } } } ``` ### 前缀 目前并不是所有的浏览器都实现了API的前缀版本(对于厂商不可知的访问Fullscreen API,你可以使用Fscreen)。 下面是总结前缀和名称差异的表格: | Standard | Blink \(Chrome & Opera\)、Edge | Gecko \(Firefox\) | Internet Explorer11 | | :--- | :--- | :--- | :--- | | Document.fullscreen | webkitIsFullScreen | mozFullScreen | - | | Document.fullscreenEnabled | webkitFullscreenEnabled | mozFullScreenEnabled | msFullscreenEnabled | | Document.fullscreenElement | webkitFullscreenElement | mozFullScreenElement | msFullscreenElement | | Document.onfullscreenchange | onwebkitfullscreenchange | onmozfullscreenchange | MSFullscreenChange | | Document.onfullscreenerror | onwebkitfullscreenerror | onmozfullscreenerror | MSFullscreenError | | Document.exitFullscreen\(\) | webkitExitFullscreen\(\) | mozCancelFullScreen\(\) | msExitFullscreen\(\) | | Element.requestFullscreen\(\) | webkitRequestFullscreen\(\) | mozRequestFullScreen\(\) | msRequestFullscreen\(\) | ## 在线和离线事件 为了构建一个支持离线的 web 应用,你需要知道你的应用何时真正处于离线状态。同时,你还需要知道应用何时重新回到了「在线」状态。实际上,我们可以把需求分解成如下内容: 1. 你需要知道用户何时回到在线状态,这样你就可以与服务器重新同步。 2. 你需要知道用户何时处于离线状态,这样你就可以将对服务器的请求放入队列中以便稍后使用。 这便是在线/离线事件所要处理的过程。 ### API #### `navigator.onLine` [`navigator.onLine`](https://developer.mozilla.org/en/DOM/window.navigator.onLine) 是一个值为 `true`/`false` \(`true` 表示在线, `false` 表示离线\) 的属性。当用户通过选择对应的菜单项 \(Firefox 中为 文件 -&gt; 离线工作\) 切换到「离线模式」时,这个值就会被更新。 此外,当浏览器长时间无法连接到网络时,该值也会被更新。根据如下规范: > `由于用户点击一个链接或是脚本请求一个远程页面(或者类似的操作失败了)从而导致户代理无法访问网络时, navigator.onLine` > 属性返回 false ... 在 Firefox 2 中,当在浏览器的离线模式中来回切换时会更新该属性。 Windows, Linux, 和 OS X 上的 Firefox 41 会在操作系统报告网络连接变化时更新该属性。 该属性存在于旧版本的 Firefox 与 Internet Explorer \(规范就是以这些旧有实现为基础\),因此你现在就可以使用该属性。Firefox 2实现了网络状态自动检测。 **`「online」与「offline」` 事件** Firefox 3 引入了两个新事件:「`online」与「offline」。当浏览器从在线与离线状态中切换时,这两个事件会在页面的<body>` 上触发。此外,该事件会从 `document.body 冒泡到document 上,最后到达window。两个事件都无法被取消`\(你无法阻止用户进入在线或离线状态\)。 你可以使用几种熟悉的方式来注册事件: * 在 `window,document,或document.body 上使用`[`addEventListener`](https://developer.mozilla.org/en/DOM/element.addEventListener) * 将 `document`或 `document.body 的.ononline`或 `.onoffline`属性设置为一个 JavaScript`Function`对象。\(**注意:**由于兼容性原因,不能使用 `window.ononline`或 `window.onoffline`。\) * 在 HTML 标记中的 `<body>标签上指定ononline="..."` 或 `onoffline="..."`特性。 #### 示例 ``` window.addEventListener('load', function() { var status = document.getElementById("status"); var log = document.getElementById("log"); function updateOnlineStatus(event) { var condition = navigator.onLine ? "online" : "offline"; status.className = condition; status.innerHTML = condition.toUpperCase(); log.insertAdjacentHTML("beforeend", "Event: " + event.type + "; Status: " + condition); } window.addEventListener('online', updateOnlineStatus); window.addEventListener('offline', updateOnlineStatus); }); ``` #### 注意 如果浏览器没有实现该 API,你可以使用其他方式来检测是否离线,包括 [AppCache 错误事件](http://www.html5rocks.com/en/mobile/workingoffthegrid.html#toc-appcache) 和 [XMLHttpRequest 的响应](http://www.html5rocks.com/en/mobile/workingoffthegrid.html#toc-xml-http-request)。