原来我对这些 Web API
一无所知,又又又打开了个人新世界,将来 Web
能够作到更多,早日一统江湖吧,吼吼吼。html
虽然这些 API
不少目前还存在兼容性的问题,可是仍是有必要了解一下的,文中的代码,我已经都测试过了。但愿你看完以后可以有所收获。git
原文连接: https://blog.bitsrc.io/10-use...
你可能已经知道并使用更为流行的 Web APIs
(Web Worker
,Fetch
等),但也有少数不那么流行的 API
,我我的喜欢使用,并建议你也尝试一下。github
这篇文章中描述的全部 Web API
示例均可以在这里找到:web
Web Audio API
容许你在 Web
上操做音频流。它可用于向网络上的音频源添加效果和滤镜。数组
音频源能够来自 <audio>
,视频/音频源文件或音频网络流。浏览器
让咱们看一个简单的例子:
<body> <header> <h2>Web APIs<h2> </header> <div class="web-api-cnt"> <div class="web-api-card"> <div class="web-api-card-head"> Demo - Audio </div> <div class="web-api-card-body"> <div id="error" class="close"></div> <div> <audio controls src="./lovely.mp4" id="audio"></audio> </div> <div> <button onclick="audioFromAudioFile.init()">Init</button> <button onclick="audioFromAudioFile.play()">Play</button> <button onclick="audioFromAudioFile.pause()">Pause</button> <button onclick="audioFromAudioFile.stop()">Stop</button> </div> <div> <span>Vol: <input onchange="audioFromAudioFile.changeVolume()" type="range" id="vol" min="1" max="3" step="0.01" value="1" /></span> <span>Pan: <input onchange="audioFromAudioFile.changePan()" type="range" id="panner" min="-1" max="1" step="0.01" value="0" /></span> </div> </div> </div> </div> </body> <script> const l = console.log let audioFromAudioFile = (function () { var audioContext var volNode var pannerNode var mediaSource function init() { l("Init") try { audioContext = new AudioContext() mediaSource = audioContext.createMediaElementSource(audio) volNode = audioContext.createGain() volNode.gain.value = 1 pannerNode = new StereoPannerNode(audioContext, { pan: 0 }) mediaSource.connect(volNode).connect(pannerNode).connect(audioContext.destination) console.log(volNode) } catch (e) { error.innerHTML = "The Web Audio API is not supported in this device." error.classList.remove("close") } } function play() { audio.play() } function pause() { audio.pause() } function stop() { audio.stop() } function changeVolume() { volNode.gain.value = document.getElementById('vol').value } function changePan() { pannerNode.gain.value = tdocument.getElementById('panner').value } return { init, play, pause, stop, changePan, changeVolume } })() </script>
译者注:源代码有点小问题,上面的代码我已经修改过,能够运行,不过mp4文件换成本身本地有的。网络
此示例将音频从 <audio>
元素传递到 AudioContext
。声音效果(例如声像)在添加到音频输出(扬声器)以前已添加到音频源。并发
单击 Init
按钮将调用 init
函数。这将建立一个 AudioContext
实例并将其设置为 audioContext
。接下来,它建立一个媒体源 createMediaElementSource(audio)
,将音频元素做为音频源传递。app
createGain
建立音量节点 volNode
。在这里,咱们调整音频的音量。接下来,使用 StereoPannerNode
设置声像效果。最后,将节点链接到媒体源。
咱们有一个音量和声像的滑块,拖动它们会影响音量和音频的声像效果。
这个例子有问题,因此该连接也没法正常使用,能够拷贝上面的代码在本地运行
Fullscreen API
让咱们可以在 Web app
中启用全屏模式。它使你能够选择要在全屏模式下查看的元素。在 Android
手机中,它将删除浏览器窗口和 Android
顶部状态栏(显示网络状态,电池状态等的地方)。
方法:
requestFullscreen
在系统上以全屏模式显示选定的元素,从而关闭其余应用程序以及浏览器和系统UI元素。exitFullscreen
将全屏模式退出到正常模式。让咱们看一个简单的示例,其中咱们可使用全屏模式观看视频:
<body> <header> <h2>Web APIs<h2> </header> <div class="web-api-cnt"> <div class="web-api-card"> <div class="web-api-card-head"> Demo - Fullscreen </div> <div class="web-api-card-body"> <div id="error" class="close"></div> <div> This API makes fullscreen-mode of our webpage possible. It lets you select the Element you want to view in fullscreen-mode, then it shuts off the browsers window features like URL bar, the window pane, and presents the Element to take the entire width and height of the system. In Android phones, it will remove the browsers window and the Android UI where the network status, battery status are displayed, and display the Element in full width of the Android system. </div> <div class="video-stage"> <video id="video" src="./lovely.mp4"></video> <button onclick="toggle()">Toogle Fullscreen</button> </div> <div> This API makes fullscreen-mode of our webpage possible. It lets you select the Element you want to view in fullscreen-mode, then it shuts off the browsers window features like URL bar, the window pane, and presents the Element to take the entire width and height of the system. In Android phones, it will remove the browsers window and the Android UI where the network status, battery status are displayed, and display the Element in full width of the Android system. </div> </div> </div> </div> </body> <script> const l = console.log function toggle() { const videoStageEl = document.querySelector(".video-stage") console.log(videoStageEl.requestFullscreen) if (videoStageEl.requestFullscreen) { if (!document.fullscreenElement) { videoStageEl.requestFullscreen() } else { document.exitFullscreen() } } else { error.innerHTML = "Fullscreen API not supported in this device." error.classList.remove("close") } } </script>
video
元素在 div#video-stage
元素中,并带有一个按钮 Toggle Fullscreen
。
当咱们单击 Toggle Fullscreen
按钮时,咱们但愿使元素 div#video-stage
变为全屏显示。
看一下 toggle
这个函数:
function toggle() { const videoStageEl = document.querySelector(".video-stage") if(!document.fullscreenElement) videoStageEl.requestFullscreen() else document.exitFullscreen() }
获取 div#video-stage
元素,并将其实例保留在 videoStageEl
上。
咱们用过 document.fullsreenElement
属性能够知道该元素是否处于全屏模式,若是不是全屏模式,能够调用 videoStageEl
上的 requestFullscreen()
方法,使 div#video-stage
接管整个设备视图。
若是在全屏模式下点击 Toggle Fullscreen
按钮,将会调用 document.exitFullcreen()
,从而返回到普通视图。
注:该连接中的视频资源找不到了,可是全屏功能是正常的,你们也能够在本地测试
Web Speech API
让咱们能够将语音合成和语音识别功能添加到Web应用中。
使用此 API
,咱们将可以向Web应用发出语音命令,就像在 Android
上经过其 Google Speech
或像在Windows
中使用 Cortana
同样。
让咱们看一个简单的例子。咱们将看到如何使用 Web Speech API
实现文本到语音和语音到文本的转换。
<body> <header> <h2>Web APIs<h2> </header> <div class="web-api-cnt"> <div id="error" class="close"></div> <div class="web-api-card"> <div class="web-api-card-head"> Demo - Text to Speech </div> <div class="web-api-card-body"> <div> <input placeholder="Enter text here" type="text" id="textToSpeech" /> </div> <div> <button onclick="speak()">Tap to Speak</button> </div> </div> </div> <div class="web-api-card"> <div class="web-api-card-head"> Demo - Speech to Text </div> <div class="web-api-card-body"> <div> <textarea placeholder="Text will appear here when you start speeaking." id="speechToText"></textarea> </div> <div> <button onclick="tapToSpeak()">Tap and Speak into Mic</button> </div> </div> </div> </div> </body> <script> try { var speech = new SpeechSynthesisUtterance() var recognition = new SpeechRecognition() } catch (e) { error.innerHTML = "Web Speech API not supported in this device." error.classList.remove("close") } function speak() { speech.text = textToSpeech.value speech.volume = 1 speech.rate = 1 speech.pitch = 1 alert(window.speechSynthesis) window.speechSynthesis.speak(speech) } function tapToSpeak() { recognition.onstart = function () { } recognition.onresult = function (event) { const curr = event.resultIndex const transcript = event.results[curr][0].transcript speechToText.value = transcript } recognition.onerror = function (ev) { console.error(ev) } recognition.start() } </script>
第一个演示 Demo - Text to Speech
演示了经过一个简单的输入框接收输入的文字以及一个按钮点击后输出语音的功能。
看一下
speak
函数:
function speak() { speech.text = textToSpeech.value speech.volume = 1 speech.rate = 1 speech.pitch = 1 window.speechSynthesis.speak(speech) }
它实例化 SpeechSynthesisUtterance()
对象,将咱们在输入框中输入的文本转换为语音。而后,调用语音对象 SpeechSynthesis
的 speak
函数,使输入框中的文本在咱们的扬声器中放出。
第二个演示 Demo - Speech to Text
是语音识别演示。咱们点击 Tap and Speak into Mic
按钮,对着麦克风说话,咱们说的单词就被翻译成了文本。
Tap and Speak into Mic
按钮单击后调用 tapToSpeak
函数:
function tapToSpeak() { recognition.onstart = function () { } recognition.onresult = function (event) { const curr = event.resultIndex const transcript = event.results[curr][0].transcript speechToText.value = transcript } recognition.onerror = function (ev) { console.error(ev) } recognition.start() }
很简单,实例化 SpeechRecognition
,而后注册事件处理程序和回调。在语音识别开始时调用 onstart
,在发生错误时调用 onerror
。每当语音识别捕获到一条线时,就会调用 onresult
。
能够看到,在 onresult
回调中,咱们提取文本并将其设置到文本区域。因此当咱们对着麦克风说话时,这些内容会输出在文本区域中。
译者:个人爪机和电脑 Chrome
(V83) 都不能支持该 API
。
实验技术
Bluetooth API
使得咱们能够访问手机上的低功耗蓝牙设备,并使用它来将网页中的数据共享到另外一台设备上。
想象一下可以建立一个Web聊天应用,该应用程序能够经过蓝牙发送和接收来自其余手机的消息。
基础 API
是 navigator.bluetooth.requestDevice
。调用它将使浏览器提示用户选择一个设备,使他们能够选择一个设备或取消请求。
navigator.bluetooth.requestDevice
须要一个对象。该对象定义了用于返回与过滤器匹配的蓝牙设备的过滤器。
让咱们看一个简单的演示。本演示将使用 navigator.bluetooth.requestDeviceAPI
从BLE设备检索基本设备信息。
<body> <header> <h2>Web APIs<h2> </header> <div class="web-api-cnt"> <div class="web-api-card"> <div class="web-api-card-head"> Demo - Bluetooth </div> <div class="web-api-card-body"> <div id="error" class="close"></div> <div> <div>Device Name: <span id="dname"></span></div> <div>Device ID: <span id="did"></span></div> <div>Device Connected: <span id="dconnected"></span></div> </div> <div> <button onclick="bluetoothAction()">Get BLE Device</button> </div> </div> </div> </div> </body> <script> function bluetoothAction() { if (navigator.bluetooth) { navigator.bluetooth.requestDevice({ acceptAllDevices: true }).then(device => { dname.innerHTML = device.name did.innerHTML = device.id dconnected.innerHTML = device.connected }).catch(err => { error.innerHTML = "Oh my!! Something went wrong." error.classList.remove("close") }) } else { error.innerHTML = "Bluetooth is not supported." error.classList.remove("close") } } </script>
设备的信息会展现出来。单击按钮 Get BLE Device
则调用 bluetoothAction
函数。
function bluetoothAction() { if (navigator.bluetooth) { navigator.bluetooth.requestDevice({ acceptAllDevices: true }).then(device => { dname.innerHTML = device.name did.innerHTML = device.id dconnected.innerHTML = device.connected }).catch(err => { error.innerHTML = "Oh my!! Something went wrong." error.classList.remove("close") }) } else { error.innerHTML = "Bluetooth is not supported." error.classList.remove("close") } }
该 bluetoothAction
函数调用 navigator.bluetooth.requestDevice
API,参数设置为 acceptAllDevices: true
,这将使其扫描并列出附近全部开启了蓝牙的设备。它返回的是一个 Promise
。
译者注:电脑上 Chrome
浏览器上测试了下,是支持该API的。
Channel Messaging API
容许两个不一样的脚本运行在同一个文档的不一样浏览器上下文(好比两个 iframe
,或者文档主体和一个 iframe
,或者两个 worker
)来直接通信,在每端使用一个端口(port
)经过双向频道(channel
)向彼此传递消息。。
首先建立一个 MessageChannel
实例:
new MessageChannel()
这将返回一个 MessagePort
对象(通信信道)。
而后,就能够经过 MessagePort.port1
或 MessageChannel.port2
设置端口。
实例化 MessageChannel
的上下文将使用 MessagePort.port1
,另外一个上下文将使用 MessagePort.port2
。而后,就可使用 postMessage API
传递消息了。
每一个浏览器上下文都使用 Message.onmessage
监听消息,并使用事件的 data
属性获取消息内容。
让咱们看一个简单的示例,在这里咱们可使用 MessageChannel
在文档和 iframe
之间发送文本。
译者注:这个demo,原文中代码有错误,译者对代码进行了修改,亲测能够正常运行
<body> <header> <h2>Web APIs<h2> </header> <div class="web-api-cnt"> <div class="web-api-card"> <div class="web-api-card-head"> Demo - MessageChannel </div> <div class="web-api-card-body"> <div id="error" class="close"></div> <div id="displayMsg"> </div> <div> <input id="input" type="text" placeholder="Send message to iframe" /> </div> <div> <button onclick="sendMsg()">Send Msg</button> </div> <div> <iframe id="iframe" src="./iframe.content.html"></iframe> </div> </div> </div> </div> </body> <script> try { var channel = new MessageChannel() var port1 = channel.port1 } catch (e) { error.innerHTML = "MessageChannel API not supported in this device." error.classList.remove("close") } iframe.addEventListener("load", onLoad) function onLoad() { port1.onmessage = onMessage iframe.contentWindow.postMessage("load", '*', [channel.port2]) } function onMessage(e) { const newHTML = "<div>" + e.data + "</div>" displayMsg.innerHTML = displayMsg.innerHTML + newHTML } function sendMsg() { port1.postMessage(input.value) } </script>
注意 iframe
的标签,咱们在上面加载了一个 iframe.content.html
文件。按钮和文本是咱们键入文字并向 iframe
发送消息的地方。
const channel = new MessageChannel() const port1 = channel.port1 iframe.addEventListener("load", onLoad) function onLoad() { port1.onmessage = onMessage iframe.contentWindow.postMessage("load", '*', [channel.port2]) } function onMessage(e) { const newHTML = "<div>" + e.data + "</div>" displayMsg.innerHTML = displayMsg.innerHTML + newHTML } function sendMsg() { port1.postMessage(input.value) }
咱们初始化了 MessageChannel
和 port1
。咱们向 iframe
添加了 load
监听。在这里,咱们在port1
注册了 onmessage
监听,而后使用 postMessageAPI
将消息发送到 iframe
。看到 port2
被向下发送到 iframe
。
让咱们看一下iframe
的iframe.content.html
:
<body> <div class="web-api-cnt"> <div class="web-api-card"> <div class="web-api-card-head"> Running inside an <i>iframe</i> </div> <div class="web-api-card-body"> <div id="iframeDisplayMsg"> </div> <div> <input placeholder="Type message.." id="iframeInput" /> </div> <div> <button onclick="sendMsgiframe()">Send Msg from <i>iframe</i></button> </div> </div> </div> </div> </body> <script> var port2 window.addEventListener("message", function(e) { port2 = e.ports[0] port2.onmessage = onMessage }) function onMessage(e) { const newHTML = "<div>"+e.data+"</div>" iframeDisplayMsg.innerHTML = iframeDisplayMsg.innerHTML + newHTML } function sendMsgiframe(){ port2.postMessage(iframeInput.value) } </script>
在这里,咱们注册了一个消息事件处理函数。咱们检索 port2
并在其上设置 onmessage
事件处理函数。如今,咱们能够从 iframe
接收消息并将其发送到其父文档。
译者注:这个 try 不起来哈,能够拷贝我上面的代码在本地尝试
大多数现代移动设备包括振动硬件,其容许软件代码经过使设备摇动来向用户提供物理反馈。Vibration API
为 Web
应用程序提供访问此硬件(若是存在)的功能,若是设备不支持此功能,则不会执行任何操做。
navigator.vibrate(pattern)
控制振动,pattern
是描述振动模式的单个数字或数字数组。
navigator.vibrate(200); navigator.vibrate([200]);
以上两个例子均可以使设备振动 200 ms 并中止.
navigator.vibrate([200,300,400])
这将使设备振动200毫秒,暂停300毫秒,振动400毫秒,而后中止。
能够经过传递0,[]
,[0,0,0]
(全零数组)来中止振动。
咱们看一个简单的演示:
<body> <header> <h2>Web APIs<h2> </header> <div class="web-api-cnt"> <div class="web-api-card"> <div class="web-api-card-head"> Demo - Vibration </div> <div class="web-api-card-body"> <div id="error" class="close"></div> <div> <input id="vibTime" type="number" placeholder="Vibration time" /> </div> <div> <button onclick="vibrate()">Vibrate</button> </div> </div> </div> </div> </body> <script> if(navigator.vibrate) { function vibrate() { const time = vibTime.value if(time != "") navigator.vibrate(time) } } else { error.innerHTML = "Vibrate API not supported in this device." error.classList.remove("close") } </script>
咱们有输入和一个按钮。在输入框中输入振动的持续时间,而后点击按钮。设备将在输入的时间内振动
译者注:在安卓手机上测试正常
Broadcast Channel API
容许相同源下的不一样浏览上下文的消息或数据进行通讯。浏览上下文能够是窗口、iframe
等。
BroadcastChannel
类用于建立或加入频道。
const politicsChannel = new BroadcastChannel("politics")
politics
将是频道的名称。任何经过 politics
来初始化 BroadcastChannel
构造函数的上下文都将加入频道,它将接收在该频道上发送的任何消息,而且能够将消息发送到该频道。
若是是第一个使用 BroadcastChannel
的构造函数,politics
则会建立该频道。
要发布到频道,请使用 BroadcastChannel.postMessageAPI
要订阅频道(收听消息),请使用该 BroadcastChannel.onmessage
事件。
为了演示广播频道的用法,我构建了一个简单的聊天应用程序:
<body> <header> <h2>Web APIs<h2> </header> <div class="web-api-cnt"> <div class="web-api-card"> <div class="web-api-card-head"> Demo - BroadcastChannel </div> <div class="web-api-card-body"> <div class="page-info">Open this page in another <i>tab</i>, <i>window</i> or <i>iframe</i> to chat with them.</div> <div id="error" class="close"></div> <div id="displayMsg" style="font-size:19px;text-align:left;"> </div> <div class="chatArea"> <input id="input" type="text" placeholder="Type your message" /> <button onclick="sendMsg()">Send Msg to Channel</button> </div> </div> </div> </div> </body> <script> const l = console.log; try { var politicsChannel = new BroadcastChannel("politics") politicsChannel.onmessage = onMessage var userId = Date.now() } catch (e) { error.innerHTML = "BroadcastChannel API not supported in this device." error.classList.remove("close") } input.addEventListener("keydown", (e) => { if (e.keyCode === 13 && e.target.value.trim().length > 0) { sendMsg() } }) function onMessage(e) { const { msg, id } = e.data const newHTML = "<div class='chat-msg'><span><i>" + id + "</i>: " + msg + "</span></div>" displayMsg.innerHTML = displayMsg.innerHTML + newHTML displayMsg.scrollTop = displayMsg.scrollHeight } function sendMsg() { politicsChannel.postMessage({ msg: input.value, id: userId }) const newHTML = "<div class='chat-msg'><span><i>Me</i>: " + input.value + "</span></div>" displayMsg.innerHTML = displayMsg.innerHTML + newHTML input.value = "" displayMsg.scrollTop = displayMsg.scrollHeight } </script>
初始化了 politicsChannel
,并在 politicsChannel
上设置了一个 onmessage
事件监听器,以便它能够接收和显示消息。
点击按钮时,会调用 sendMsg
函数。它经过 BroadcastChannel#postMessageAPI
将消息发送到 politicsChannel
。初始化相同脚本的 tab
页,iframe
或 worker
都将接收今后处发送的消息,所以该页面能够接收其余上下文发送的消息。
Payment Request API
提供了为商品和服务选择支付途径的方法。
该 API
提供了一种一致的方式来向不一样的商家提供付款细节,而无需用户再次输入细节。
它向商家提供账单地址,送货地址,卡详细信息等信息。
注意: 此 API
提供了用户付款明细,但并不会带来新的付款方式。
让咱们看一个演示如何使用付款请求
API
接受信用卡付款的演示:
<body> <header> <h2>Web APIs<h2> </header> <div class="web-api-cnt"> <div class="web-api-card"> <div class="web-api-card-head"> Demo - Credit Card Payment </div> <div class="web-api-card-body"> <div id="error" class="close"></div> <div> <button onclick="buy()">Buy</button> </div> </div> </div> </div> </body> <script> const networks = ["visa", "amex"] const types = ["debit", "credit"] const supportedInstruments = [ { supportedMethods: "basic-card", data: { supportedNetworks: networks, supportedTypes: types } } ] const details = { total: { label: "Total", amount: { currency: "USD", value: "100" } }, displayItems: [ { label: "Item 1", amount: { currency: "USD", value: "50" } }, { label: "Item 2", amount: { currency: "USD", value: "50" } }, ] } try { var paymentRequest = new PaymentRequest(supportedInstruments, details) } catch (e) { error.innerHTML = "PaymentRequest API not supported in this device." error.classList.remove("close") } function buy() { paymentRequest.show().then(response => { console.log(response) }) } </script>
networks
,types
和 supportedTypes
都是描述付款方式。details
列出了咱们的购买商品和总费用。
构建 PaymentRequest
实例,paymentRequest.show()
将在浏览器中显示付款界面。并在 Promise
成功的回调中处理用户的数据。
它们是使用 Payment API
进行付款的许多配置,至少经过上面的示例,咱们已经了解了 Payment Request API
的使用方式和工做方式。
译者注:测试了下,可是没有走彻底流程,毕竟我坚定不付款的~
Resize Observer API
提供了一种方式,以任何方式调整了注册观察者的元素的大小,都通知观察者。
ResizeObserver
类提供了一个观察器,该观察器将在每一个 resize
事件上调用。
const resizeObserver = new ResizeObserver(entries => { for(const entry of entries) { if(entry.contentBoxSize) consoleo.log("element re-sized") } }) resizeObserver.observe(document.querySelector("div"))
每当调整 div
大小时,控制台上都会打印 "element re-sized"
。
让咱们看一下如何使用
Resize Observer API
的示例:
<body> <header> <h2>Web APIs<h2> </header> <div class="web-api-cnt"> <div class="web-api-card"> <div class="web-api-card-head"> Demo - ResizeObserver </div> <div class="web-api-card-body"> <div id="error" class="close"></div> <div id="stat"></div> <div id="resizeBoxCnt"> <div id="resizeBox"></div> </div> <div> <span>Resize Width:<input onchange="resizeWidth(this.value)" type="range" min="0" max="100" value="0" /></span> </div> <div> <span>Resize Height:<input onchange="resizeHeight(this.value)" type="range" min="0" max="100" value="0" /></span> </div> </div> </div> </div> </body> <script> try { var resizeObserver = new ResizeObserver(entries => { for(const entry of entries) { stat.innerHTML = "Box re-sized. Height:" + entry.target.style.height + " - Width:" + entry.target.style.width } }) resizeObserver.observe(resizeBox) } catch(e) { error.innerHTML = "ResizeObserver API not supported in this device." error.classList.remove("close") } function resizeWidth(e) { resizeBox.style.width = `${e}px` } function resizeHeight(e) { resizeBox.style.height = `${e}px` } </script>
咱们在这里有范围滑块。若是咱们滑动它们,它们将改变 idv#resizeBox
的宽高。咱们在div#resizeBox
上注册了 ResizeObserver
观察器,指示该消息指示框已被调整大小以及其高度和宽度的当前值。
尝试滑动范围滑块,你将看到 div#resizeBox
宽高的变化,此外,咱们还将看到 div#stat
框中显示的信息。
Pointer Lock API
对于须要大量的鼠标输入来控制运动,旋转物体,以及更改项目的应用程序来讲很是有用。对高度视觉化的应用程序尤为重要,例如那些使用第一人称视角的应用程序,以及 3D 视图和建模。
方法:
requestPointerLock
:此方法将从浏览器中删除鼠标并发送鼠标状态事件。这将持续到调用 document.exitPointerLock
为止。document.exitPointerLock
:此 API
释放鼠标指针锁定并恢复鼠标光标。让咱们来看一个例子:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> #box { background-color: green; width: 100%; height: 400px; position: relative; } #ball { border-radius: 50%; background-color: red; width: 50px; height: 50px; position: absolute; } </style> </head> <body> <header> <h2>Web APIs<h2> </header> <div class="web-api-cnt"> <div class="web-api-card"> <div class="web-api-card-head"> Demo - PointerLock </div> <div class="web-api-card-body"> <div id="error" class="close"></div> <div id="box"> <div id="ball"></div> </div> </div> </div> </div> </body> <script> const l = console.log box.addEventListener("click", () => { if (box.requestPointerLock) box.requestPointerLock() else { error.innerHTML = "PointerLock API not supported in this device." error.classList.remove("close") } }) document.addEventListener("pointerlockchange", (e) => { document.addEventListener("mousemove", (e) => { const { movementX, movementY } = e ball.style.top = movementX + "px" ball.style.left = movementY + "px" }) }) </script> </html>
在 div#box
中咱们有一个 div#box
和 div#ball
。
咱们在 div#box
上设置了一个 click
事件,当单击它时会调用 requestPointerLock()
,这会使光标消失。
PointerLock
有一个 pointerlockchange
事件监听器。当指针锁定状态更改时,将触发此事件。在其回调中,咱们将其添加到 mousemove
事件。在当前浏览器选项卡上移动鼠标时,将触发其回调。在此回调中,所以咱们使用它来获取鼠标的当前X和Y位置。使用此信息,咱们能够设置 div#ball
的 top
和 left
样式属性,所以,当鼠标移动时,咱们会看到一个跳舞的球(译者注:原文的demo中没有设置div#ball
的定位,所以修改 top
和 left
值时,小球位置没有变化)。
鼠标事件的两个新参数 —— movementX
和 movementY
提供了鼠标位置的变化状况。当指针锁定被启动以后,正常的 MouseEvent
属性 clientX
, clientY
, screenX
, 和 screenY
,保持不变,就像鼠标没有在移动同样。
译者注:这个demo有点问题,所以try不起来,你们能够拷贝我上面的代码在本地 try.
Web日趋复杂。愈来愈多的原生功能正在使用中,这是由于Web用户的数量远远大于原生APP用户。用户在原生应用上的体验被带到Web上,这样他们无需去使用原生应用。
好嘛,若是看到这里,说明是真爱了。要不要给个人 Github 增长一个 star。