掃二維碼與項(xiàng)目經(jīng)理溝通
我們在微信上24小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
首先問大家一個(gè)問題,現(xiàn)在有一項(xiàng)業(yè)務(wù)需求,這個(gè)需求使用客戶端應(yīng)用實(shí)現(xiàn)還是網(wǎng)頁來實(shí)現(xiàn)你會(huì)考慮哪些因素呢?

讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來自于我們對這個(gè)行業(yè)的熱愛。我們立志把好的技術(shù)通過有效、簡單的方式提供給客戶,將通過不懈努力成為客戶在信息化領(lǐng)域值得信任、有價(jià)值的長期合作伙伴,公司提供的服務(wù)項(xiàng)目有:申請域名、虛擬主機(jī)、營銷軟件、網(wǎng)站建設(shè)、華池網(wǎng)站維護(hù)、網(wǎng)站推廣。
曾幾何時(shí),想到網(wǎng)頁可能我們第一時(shí)間想到的就是一些靜態(tài)頁面,但是經(jīng)過數(shù)十年的蓬勃發(fā)展,網(wǎng)頁開始承接越來越復(fù)雜的需求,包括復(fù)雜的管理系統(tǒng)、網(wǎng)絡(luò)直播、云游戲等能力。
但或許你仍然會(huì)認(rèn)為相比可以和系統(tǒng)底層直接交互的原生客戶端應(yīng)用還是太弱了,我們可能會(huì)因?yàn)闉g覽器“缺失” 了某一項(xiàng)能力而被迫選擇開發(fā)一個(gè)客戶端應(yīng)用。
?為此 Google 啟動(dòng)了一個(gè)名為 Fugu 的項(xiàng)目,它的目標(biāo)就是讓開發(fā)者能夠在 Web 生態(tài)中做任何事情,包括以前只有客戶端應(yīng)用才能做的事情。
在 Fugu 項(xiàng)目中, Google 為 Chrome 規(guī)劃了數(shù)百項(xiàng)能力,如今進(jìn)展已經(jīng)過半,我們一起來看看瀏覽器現(xiàn)在擁有了哪些或許你還不知道的能力吧 ...
和藍(lán)牙設(shè)備交互 【Chrome 56】
?Web Bluetooth API 為瀏覽器提供了連接藍(lán)牙設(shè)備并與之交互的能力。
這意味著:你的網(wǎng)站可以直接連接你的運(yùn)動(dòng)手表,查看步數(shù)、心率等數(shù)據(jù),可以直接控制你的藍(lán)牙音響等等。而這些能力,之前你必須要下載一個(gè) App 才能實(shí)現(xiàn)了 ...
獲取是否支持藍(lán)牙連接:
navigator.bluetooth.getAvailability().then((available) {
if (available) {
console.log("設(shè)備支持藍(lán)牙連接!");
} else {
console.log("設(shè)備不支持藍(lán)牙");
}
});連接到藍(lán)牙設(shè)備:
navigator.bluetooth.requestDevice({ filters: [{ services: ['battery_service'] }] })
.then(device {
// 獲取設(shè)備名稱 [ConardLi]
console.log(device.name);
// 連接遠(yuǎn)程 GATT Server.
return device.gatt.connect();
})
.then(server { /* … */ })
.catch(error { console.error(error); });了解更多:https://developer.chrome.com/articles/bluetooth/
和 USB 設(shè)備交互【Chrome 61】
?Web USB API 為瀏覽器提供了和 USB 設(shè)備進(jìn)行交互的能力。
說到 USB ,你很有可能會(huì)立即想到鍵盤、鼠標(biāo)、音頻、視頻和一些存儲(chǔ)設(shè)備。
這些非標(biāo)準(zhǔn)化的 USB 設(shè)備通常需要硬件供應(yīng)商編寫特定于平臺(tái)的驅(qū)動(dòng)程序和 SDK,開發(fā)非常繁瑣。
如果可以在 Web 上和 USB 進(jìn)行交互,這意味著硬件制造商將能夠?yàn)槠湓O(shè)備構(gòu)建跨平臺(tái)的 JavaScript SDK,這將極大簡化一個(gè) SDK 的開發(fā)成本!另外,通過將 USB 引入 Web,也可以使得 USB 更安全、更易于使用。
?下面?是一段簡單地獲取 USB 設(shè)備的代碼:
navigator.usb.getDevices().then(devices {
devices.forEach(device {
console.log(device.productName); // "[ConardLi] Arduino Micro "
console.log(device.manufacturerName); // "[ConardLi] Arduino LLC"
});
})你還可以在 Chrome 的內(nèi)部頁面 about://device-log 方便的調(diào)試 USB 設(shè)備:
了解更多:https://wicg.github.io/webusb/
在以前,我們一般使用 document.execCommand() 進(jìn)行剪貼板交互。雖然瀏覽器兼容性還不錯(cuò),但這種剪切和粘貼的方法有明顯的缺點(diǎn):剪貼板訪問是同步的,只能讀寫 DOM。
對于少量文本的剪貼還好,但如果剪貼內(nèi)容較大,在安全粘貼內(nèi)容之前,可能還需要進(jìn)行耗時(shí)的清理或圖像解碼,瀏覽器可能還需要從粘貼的文檔加載或內(nèi)聯(lián)鏈接資源,這種情況下用戶體驗(yàn)就比較糟糕了。
Asynchronous Clipboard API 的出現(xiàn)解決了這些問題,比如我們要將一段文本復(fù)制到剪貼板,可以調(diào)用一個(gè)異步的 writeText 函數(shù):
async function copyPageUrl() {
try {
await navigator.clipboard.writeText(location.href);
console.log('Page URL 已賦值到剪貼板');
} catch (err) {
console.error('失敗了~);
}
}從剪貼板讀取數(shù)據(jù)一樣也可以是異步的:
async function getClipboardContents() {
try {
const text = await navigator.clipboard.readText();
console.log('粘貼文本: ', text);
} catch (err) {
console.error('讀取剪貼板文本失敗: ', err);
}
}另外,document.execCommand() 還有一個(gè)非常明顯的問題就是權(quán)限控制過于寬松了,在很多情況下我們可能會(huì)擔(dān)心網(wǎng)站是否會(huì)私自讀取我們剪貼板的信息,Asynchronous Clipboard API 僅支持 HTTPS 頁面,另外在讀取剪貼板是會(huì)向用戶發(fā)送許可,這保證了網(wǎng)頁必須在用戶同意的情況下才能讀取剪貼板:
了解更多:https://developer.mozilla.org/docs/Web/API/Clipboard_API
getInstalledRelatedApps 方法可以讓瀏覽器知道某些應(yīng)用程序是否已在電腦上安裝了,當(dāng)然目前僅限于 Android、Windows 或 PWA 應(yīng)用。
const relatedApps = await navigator.getInstalledRelatedApps();
relatedApps.forEach((app) => {
// 注意只能獲取到已經(jīng)授權(quán)的應(yīng)用,并不是所有應(yīng)用
console.log(app.id, app.platform, app.url);
});
想象一下你開發(fā)了一個(gè)產(chǎn)品的官網(wǎng),在用戶下載頁面你可以根據(jù)應(yīng)用的安裝狀態(tài)提示用戶是下載還是更新,甚至可以直接打開應(yīng)用...
了解更多:https://github.com/WICG/get-installed-related-apps
在以前,能夠在移動(dòng)設(shè)備上訪問用戶的聯(lián)系人一直是移動(dòng) Web 應(yīng)用開發(fā)者最想要的功能之一,這也是促使他們必須選擇開發(fā)一個(gè) App 的重要原因...
Contact Picker API 為瀏覽器提供了獲取手機(jī)聯(lián)系人的能力。
假如我們有一個(gè)基于 Web 的電子郵件客戶端,可以直接使用 Contact Picker API來選擇電子郵件的收件人。一個(gè)基于 Web 的 IP 語音應(yīng)用程序可以直接查找要撥打的電話號(hào)碼?;蛘咭恍?Web 社交應(yīng)用可以幫助用戶發(fā)現(xiàn)哪些朋友已經(jīng)加入了。
比如,你打開一個(gè)網(wǎng)頁游戲,他可以直接告訴你,你的好兄弟 ConardLi 也在玩喲,快和他一起組隊(duì)來砍我吧...
下面是一個(gè)簡單的使用示例:
const props = ['name', 'email', 'tel', 'address', 'icon'];
const opts = {multiple: true};
try {
const contacts = await navigator.contacts.select(props, opts);
handleResults(contacts);
} catch (ex) {
// 一些錯(cuò)誤...
}
了解更多:https://wicg.github.io/contact-api/spec/
?在以前,瀏覽器提供了諸如 HTMLMediaElement、WebAudio、WebRTC 等實(shí)現(xiàn)媒體編解碼器能力的 API,但是沒有通用的方法來靈活配置和使用這些媒體編解碼器。因此,在有性能差、耗電快等問題的情況下,許多 Web 應(yīng)用還是會(huì)求助于在 JavaScript 或 WebAssembly 中實(shí)現(xiàn)媒體編解碼器。
WebCodecs 為網(wǎng)頁提供了對內(nèi)置(軟件和硬件)媒體編碼器和解碼器的高效訪問能力。
這項(xiàng)能力為網(wǎng)頁直播、云游戲等對流媒體處理性能要求較高的場景下大地來了很大便利。
下面是一個(gè)從視頻渲染到 Canvas 來實(shí)現(xiàn)極低延遲流的示例:
function onDecoderError(error) { ... }
function streamEncodedChunks(decodeCallback) { ... }
const canvasElement = document.getElementById("canvas");
const canvasContext = canvas.getContext('2d', canvasOptions)
function paintFrameToCanvas(videoFrame) {
canvasContext.drawImage(frame, 0, 0);
frame.close();
}
const videoDecoder = new VideoDecoder({
output: paintFrameToCanvas,
error: onDecoderError
});
videoDecoder.configure({codec: 'vp8'}).then(() {
streamEncodedChunks(videoDecoder.decode.bind(videoDecoder));
}).catch(() {});了解更多:https://github.com/w3c/webcodecs/blob/main/explainer.md
?App Badging API 可以讓 Web 應(yīng)用為圖標(biāo)添加一些徽章。
比如一個(gè) Web 聊天室可以在徽章上顯示未讀的消息數(shù);一個(gè) Web 象棋游戲可以通過標(biāo)記提醒輪到你下棋了;一些長耗時(shí)的后臺(tái)任務(wù)可以通過標(biāo)記告訴你任務(wù)已經(jīng)成功 ...
下面是一個(gè)簡單的代碼示例:
// 設(shè)置徽章
const unreadCount = 17;
navigator.setAppBadge(unreadCount).catch((error) => {
// 異常捕獲...
});
// 清除徽章
navigator.clearAppBadge().catch((error) => {
// 異常捕獲...
});
了解更多:https://w3c.github.io/badging/
?在以前,我們想在 Web 上讀取一些圖片上的數(shù)據(jù)是相當(dāng)困難的,比如開發(fā)者想在客戶端提取一些些特征來構(gòu)建一個(gè)二維碼閱讀器,必須要依賴一個(gè)龐大的外部 JavaScript 庫,而且性能可能很差。
但是,包括 Android、iOS 和 macOS 在內(nèi)的操作系統(tǒng),以及相機(jī)模塊中的硬件芯片,通常已經(jīng)具有高性能和高度優(yōu)化的特征檢測器,例如 Android 的 FaceDetector 或 iOS 的 CIDetector 通用特征檢測器。
Shape Detection API 通過一組 JavaScript 接口公開了這些實(shí)現(xiàn)。目前支持的功能有人臉檢測、條碼檢測以及文字檢測,這意味著我們可以在 Web 上實(shí)現(xiàn)下面的功能:
下面是一段簡單的人臉識(shí)別代碼:
// [ConardLi]
const faceDetector = new FaceDetector({
// 限制識(shí)別人臉的數(shù)量
maxDetectedFaces: 5,
// 降低精度提升速度
fastMode: false
});
try {
const faces = await faceDetector.detect(image);
faces.forEach(face drawMustache(face));
} catch (e) {
console.error('Face detection failed:', e);
}
了解更多:https://wicg.github.io/shape-detection-api/
當(dāng)我們在一些網(wǎng)站上進(jìn)行注冊或登錄時(shí),可能需要驗(yàn)證手機(jī)號(hào)。網(wǎng)頁一般會(huì)發(fā)送一個(gè)驗(yàn)證碼,我們需要將驗(yàn)證碼提交到網(wǎng)頁上來完成驗(yàn)證。但是切到短信后復(fù)制驗(yàn)證碼,再回來提交整個(gè)過程是比較繁瑣的。
WebOTP API 為瀏覽器提供了快捷讀取短信驗(yàn)證碼的能力。
用法也非常簡單,首先我們可以為 input 添加一個(gè) autocomplete 屬性:
然后調(diào)用 navigator.credentials 獲取驗(yàn)證碼信息:
if ('OTPCredential' in window) {
window.addEventListener('DOMContentLoaded', e {
const input = document.querySelector('input[autocomplete="one-time-code"]');
if (!input) return;
const ac = new AbortController();
const form = input.closest('form');
if (form) {
form.addEventListener('submit', e {
ac.abort();
});
}
navigator.credentials.get({
otp: { transport:['sms'] },
signal: ac.signal
}).then(otp {
input.value = otp.code;
if (form) form.submit();
}).catch(err {
console.log(err);
});
});
}了解更多:https://wicg.github.io/WebOTP/
試?想一下,當(dāng)你在某個(gè)網(wǎng)站上看著菜譜做飯,由于長時(shí)間未操作手機(jī)自動(dòng)鎖屏了,你還需要去定期觸碰一下手機(jī),是不是有點(diǎn)頭大。
Screen Wake Lock API 可體讓瀏覽器在網(wǎng)頁需要繼續(xù)運(yùn)行時(shí)防止調(diào)暗或鎖定屏幕。
使用方式也很簡單,可以直接調(diào)用 navigator.wakeLock.request() 方法,返回一個(gè) WakeLockSentinel 對象。
據(jù)說在實(shí)施了 Screen Wake Lock API 后,美國主要烹飪網(wǎng)站 Betty Crocker 的用戶購買意向指標(biāo)增加了 300% ...
了解更多:https://w3c.github.io/screen-wake-loc?k
在以前,我們只能通過 在瀏覽器上訪問文件,需要寫出類似下面的代碼:
const openFile = async () => {
return new Promise((resolve) => {
const input = document.createElement('input');
input.type = 'file';
input.addEventListener('change', () {
resolve(input.files[0]);
});
input.click();
});
};File System Access API 為瀏覽器提供了更好的和文件系統(tǒng)交互的能力:
const openFile = async () => {
try {
// Always returns an array.
const [handle] = await window.showOpenFilePicker();
return handle.getFile();
} catch (err) {
console.error(err.name, err.message);
}
};了解更多:https://wicg.github.io/file-system-access/
?NFC 代表 Near Field Communications,這是一種以 13.56 MHz 頻率運(yùn)行的短距離無線技術(shù),能夠在小于 10 厘米的距離內(nèi)實(shí)現(xiàn)設(shè)備之間的通信,傳輸速率高達(dá) 424 kbit/s。
Web NFC 為網(wǎng)站提供了在靠近用戶設(shè)備時(shí)讀取和寫入 NFC 標(biāo)簽的能力,這意味著你只需要打開一個(gè)網(wǎng)站就可以刷地鐵進(jìn)站了...
要掃描 NFC 標(biāo)簽,首先需要實(shí)例化一個(gè) NDEFReader 對象,并調(diào)用 scan 方法,下面是一個(gè)簡單的代碼示例:
const ndef = new NDEFReader();
ndef.scan().then(() {
console.log("掃描開始");
ndef.onreadingerror = () {
console.log("無法讀取NFC數(shù)據(jù)!");
};
ndef.onreading = event {
console.log("NFC數(shù)據(jù)讀取成功...");
};
}).catch(error {
console.log(`Error! Scan failed to start: ${error}.`);
});
了解更多:https://wicg.github.io/file-system-access/
?WebHID API 為瀏覽器提供了和人機(jī)接口設(shè)備(簡稱 HID)交互的能力。
比如鍵盤、鼠標(biāo)、觸摸板、游戲手柄等都屬于 HID 設(shè)備,WebHID API 提供了一系列 JavaScript API 來和這些設(shè)備進(jìn)行交互。而在以前,你必須要有一個(gè)特定的游戲主機(jī)才可以...
想象一下,以后再也不用糾結(jié)于國行外行了,因?yàn)槟阒苯涌梢栽诰W(wǎng)頁里打開 Switch 游戲了...
下面是一個(gè)簡單的代碼示例:
// 在具有 Switch Joy-Con USB 供應(yīng)商/產(chǎn)品id的設(shè)備上進(jìn)行篩選。
const filters = [
{
vendorId: 0x057e, // Nintendo Co., Ltd
productId: 0x2006 // Joy-Con Left
},
{
vendorId: 0x057e, // Nintendo Co., Ltd
productId: 0x2007 // Joy-Con Right
}
];
// 提示用戶選擇 Joy-Con 設(shè)備。
const [device] = await navigator.hid.requestDevice({ filters });
了解更多:https://wicg.github.io/webhid/index.html
串行接口(Serial port),也稱串行接口或串行端口,串行通信接口,COM接口,簡稱串口。主要用于串行式逐位數(shù)據(jù)傳輸。
?Web Serial API 為網(wǎng)站提供了一種使用 JavaScript 讀取和寫入串行設(shè)備的方法。
這樣,我們的網(wǎng)站?又能控制更多設(shè)備了,比如打印機(jī)、路由器、交換機(jī)等等。
下面是一個(gè)簡單的代碼示例:
document.querySelector('button').addEventListener('click', async () => {
// 提示用戶選擇串口
const port = await navigator.serial.requestPort();
});從串口讀取數(shù)據(jù):
const reader = port.readable.getReader();
// 監(jiān)聽來自串行設(shè)備的數(shù)據(jù)
while (true) {
const { value, done } = await reader.read();
if (done) {
reader.releaseLock();
break;
}
console.log(value);
}
同樣的,你也可以在 Chrome 的 about://device-log 對串口設(shè)備進(jìn)行調(diào)試。
?Idle Detection API 為網(wǎng)站提供了檢測用戶當(dāng)前是否空閑(例如在一段時(shí)間內(nèi)沒有與鍵盤、鼠標(biāo)、屏幕的交互)的能力。
例如,一個(gè) Web 聊天室應(yīng)用可以讓你知道你的好友當(dāng)前是否在線,下面是一個(gè)空閑檢測的簡單示例:
// [ConardLi] 創(chuàng)建空閑探測器
const idleDetector = new IdleDetector();
// 設(shè)置一個(gè)在用戶空閑時(shí)觸發(fā)的監(jiān)聽器
idleDetector.addEventListener('change', () {
const uState = idleDetector.userState;
const sState = idleDetector.screenState;
console.log(`Idle change: ${uState}, ${sState}.`);
});
// 開始監(jiān)聽
await idleDetector.start({
threshold: 60000,
signal,
});
了解更多:https://wicg.github.io/idle-detection
?WebTransport 是一種新的 API,使用 HTTP/3 協(xié)議作為雙向傳輸,為網(wǎng)站提供低延遲、雙向、客戶端-服務(wù)器消息傳遞能力。
你可能會(huì)問和 WebSockets 的區(qū)別是啥?
WebSockets 的消息流特點(diǎn)是單一、可靠、有序,這對于某些場景的通信需求來說是很好的;但是 WebTransport 的數(shù)據(jù)的特點(diǎn)是低延遲,但不保證可靠性或排序,因?yàn)樗讓邮褂玫?nbsp;QUIC 握手比通過 TLS 啟動(dòng) TCP 更快。
如果你的數(shù)據(jù)通信需要非常好的性能,但是對偶爾的丟包和排序可以容忍,比如一些網(wǎng)頁游戲的場景,WebTransport 是一個(gè)更好的選擇。
下面是一個(gè)簡單的使用示例:
// 向服務(wù)器發(fā)送數(shù)據(jù)
const writer = transport.datagrams.writable.getWriter();
const data1 = new Uint8Array([65, 66, 67]);
const data2 = new Uint8Array([68, 69, 70]);
writer.write(data1);
writer.write(data2);
// 從服務(wù)器讀取數(shù)據(jù)
const reader = transport.datagrams.readable.getReader();
while (true) {
const {value, done} = await reader.read();
if (done) {
break;
}
// 值為 Uint8Array。
console.log(value);
}
了解更多:https://wicg.github.io/web-transport/#web-transport
Multi-Screen Window Placement API 為網(wǎng)頁了提供了枚舉顯示器并將窗口放置在特定屏幕上的能力。
下面是一個(gè)簡單的監(jiān)聽屏幕數(shù)量變化的示例:
// 獲取所有屏幕
const screenDetails = await window.getScreenDetails();
let cachedScreensLength = screenDetails.screens.length;
// 監(jiān)聽屏幕變化
screenDetails.addEventListener('screenschange', (event) => {
if (screenDetails.screens.length !== cachedScreensLength) {
console.log(
`屏幕數(shù)量從 ${cachedScreensLength} 變化到 ${screenDetails.screens.length}`,
);
cachedScreensLength = screenDetails.screens.length;
}
});
了解更多:https://w3c.github.io/window-placement

我們在微信上24小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流