你不知道的JavaScript APIs
最近,看到一些好用但不太常用的JS API,覺(jué)得挺不錯(cuò)的,分享給大家。
- Page Visibility API
- Web Share API
- Broadcast Channel API
- Internationalization API
下面,我們來(lái)看下應(yīng)該在哪里使用它們,以及如何使用它們。
Page Visibility API
這個(gè)APi 可以讓我們知道用戶(hù)何時(shí)離開(kāi)了頁(yè)面。準(zhǔn)確地說(shuō),只要頁(yè)面的可見(jiàn)性狀態(tài)發(fā)生變化,無(wú)論是用戶(hù)最小化、最大化窗口還是切換標(biāo)簽,該API都會(huì)觸發(fā)一個(gè)事件 visibilitychange 。
在過(guò)去,我不得不使用一些黑科技來(lái)確認(rèn)用戶(hù)是否切換了標(biāo)簽或最小化了窗口。最流行的是使用blur和foucs瀏覽器事件。
window.addEventListener("focus", function () {
// User is back on the page
// Do Something
});
window.addEventListener("blur", function () {
// User left the page
// Do Something
});
上面的代碼可以工作,但不像預(yù)期的那樣。因?yàn)閎lur事件是在頁(yè)面失去焦點(diǎn)時(shí)觸發(fā)的,所以當(dāng)用戶(hù)點(diǎn)擊搜索欄、警報(bào)對(duì)話(huà)框、控制臺(tái)或窗口邊框時(shí),它就會(huì)被觸發(fā)。所以,blur和foucs只告訴我們頁(yè)面是否被激活,但不告訴我們頁(yè)面的內(nèi)容是否被隱藏或可見(jiàn)。
案例
一般來(lái)說(shuō),我們希望使用 Page Visibility API,在用戶(hù)沒(méi)有看到頁(yè)面時(shí)停止不必要的進(jìn)程,或者執(zhí)行一些后臺(tái)操作??梢韵旅孢@幾種情況:
- 當(dāng)用戶(hù)離開(kāi)頁(yè)面時(shí),暫停視頻、輪播圖或動(dòng)畫(huà)。
- 停止一些實(shí)時(shí)獲取數(shù)據(jù)的API
- 發(fā)送一些用戶(hù)信息
如何使用它?
Page Visibility API 有兩個(gè)屬性和一個(gè)事件來(lái)訪(fǎng)問(wèn)頁(yè)面可見(jiàn)性狀態(tài)。
document.hidden它是全局可用的,而且是只讀的。盡量避免使用它,因?yàn)樗F(xiàn)在已經(jīng)被廢棄了,但是當(dāng)被訪(fǎng)問(wèn)時(shí),如果頁(yè)面是隱藏的,它將返回 true,如果是可見(jiàn)的,它將返回 false。
Document.visibilityState (只讀屬性)
返回document的可見(jiàn)性,即當(dāng)前可見(jiàn)元素的上下文環(huán)境。由此可以知道當(dāng)前文檔 (即為頁(yè)面) 是在背后,或是不可見(jiàn)的隱藏的標(biāo)簽頁(yè),或者 (正在) 預(yù)渲染??捎玫闹等缦拢?/p>
- 'visible' : 此時(shí)頁(yè)面內(nèi)容至少是部分可見(jiàn)。即此頁(yè)面在前景標(biāo)簽頁(yè)中,并且窗口沒(méi)有最小化。
- 'hidden' : 此時(shí)頁(yè)面對(duì)用戶(hù)不可見(jiàn)。即文檔處于背景標(biāo)簽頁(yè)或者窗口處于最小化狀態(tài),或者操作系統(tǒng)正處于 '鎖屏狀態(tài)'
- 'prerender' : 頁(yè)面此時(shí)正在渲染中,因此是不可見(jiàn)的 (considered hidden for purposes of document.hidden). 文檔只能從此狀態(tài)開(kāi)始,永遠(yuǎn)不能從其他值變?yōu)榇藸顟B(tài)。
visibilitychange
當(dāng)其選項(xiàng)卡的內(nèi)容變得可見(jiàn)或被隱藏時(shí),會(huì)在文檔上觸發(fā) visibilitychange (能見(jiàn)度更改) 事件。
document.addEventListener("visibilitychange", () => {
if (document.visibilityState === "visible") {
// page is visible
} else {
// page is hidden
}
});
Web Share API
Web Share API 它可以讓我們?cè)L問(wèn)操作系統(tǒng)的本地共享機(jī)制,這對(duì)移動(dòng)用戶(hù)特別有用。通過(guò)這個(gè)API,可以分享文本、鏈接和文件,而不需要?jiǎng)?chuàng)建自己的分享機(jī)制或使用第三方的機(jī)制。
使用案例
可以用它來(lái)分享網(wǎng)頁(yè)上的內(nèi)容到社交媒體上,或者把它復(fù)制到用戶(hù)的剪貼板上。
如何使用它?
網(wǎng)絡(luò)共享API給了我們兩個(gè)接口來(lái)訪(fǎng)問(wèn)用戶(hù)的共享系統(tǒng)。
navigator.canShare(data);
如果對(duì) Navigator.share() 的調(diào)用成功,則 Web Share API 的 Navigator.canShare() 方法將返回 true。data 包含要共享的數(shù)據(jù)的對(duì)象,該對(duì)象要與 Navigator.share() 方法傳遞的數(shù)據(jù)相匹配。
navigator.share(data)
Navigator.share() 方法通過(guò)調(diào)用本機(jī)的共享機(jī)制作為 Web Share API 的一部分。如果不支持 Web Share API,則此方法為 undefined。
data 包含要共享的數(shù)據(jù)的對(duì)象。必須至少指定以下字段之一??捎眠x項(xiàng)包括:
- url: 要共享的 URL( USVString )
- text: 要共享的文本( USVString )
- title: 要共享的標(biāo)題( USVString)
- files: 要共享的文件(“FrozenArray”)
該方法將會(huì)返回一個(gè) Promise。一旦用戶(hù)完成分享,這個(gè) promise 將會(huì)接受。如果指定的共享數(shù)據(jù)格式不正確,promise 將會(huì)立即拒絕;如果用戶(hù)取消了分享,promise 也會(huì)拒絕。
事例
navigator.share({
title: document.title,
text: 'Hello World',
url: 'https://developer.mozilla.org',
}); // 分享 MDN 的 URL
Broadcast Channel API
Broadcast Channel API 可以實(shí)現(xiàn)同 源 下瀏覽器不同窗口,Tab 頁(yè),frame 或者 iframe 下的 瀏覽器上下文 (通常是同一個(gè)網(wǎng)站下不同的頁(yè)面) 之間的簡(jiǎn)單通訊。
const broadcast = new BroadcastChannel("new_channel");
BroadcastChannel 接口非常簡(jiǎn)單。通過(guò)創(chuàng)建一個(gè) BroadcastChannel 對(duì)象,一個(gè)客戶(hù)端就加入了某個(gè)指定的頻道。只需要向 構(gòu)造函數(shù) 傳入一個(gè)參數(shù):頻道名稱(chēng)。如果這是首次連接到該廣播頻道,相應(yīng)資源會(huì)自動(dòng)被創(chuàng)建。
發(fā)送消息
現(xiàn)在發(fā)送消息就很簡(jiǎn)單了,只需要調(diào)用 BroadcastChannel 對(duì)象上的 postMessage() 方法即可。該方法的參數(shù)可以是任意對(duì)象。最簡(jiǎn)單的例子就是發(fā)送 DOMString 文本消息:
broadcast.postMessage("Example message");
不只是 DOMString,任意類(lèi)型的對(duì)象都可以被發(fā)送。
斷開(kāi)連接
通過(guò)調(diào)用 BroadcastChannel 對(duì)象的 close() 方法,可以離開(kāi)頻道。這將斷開(kāi)該對(duì)象和其關(guān)聯(lián)的頻道之間的聯(lián)系,并允許它被垃圾回收。
// 斷開(kāi)頻道連接
bc.close()
Internationalization API
在開(kāi)發(fā)一個(gè)網(wǎng)頁(yè)或應(yīng)用程序時(shí),需要將其內(nèi)容翻譯成其他語(yǔ)言以覆蓋更廣泛的受眾是非常常見(jiàn)的。然而,僅僅將你的網(wǎng)頁(yè)文本翻譯成你所需要的任何語(yǔ)言,并不足以使你的內(nèi)容對(duì)講該語(yǔ)言的人可用,因?yàn)橄袢掌?、?shù)字、單位等東西在不同國(guó)家是不同的,可能會(huì)給你的用戶(hù)帶來(lái)混亂。
假設(shè)你想在你的網(wǎng)頁(yè)上顯示日期 "2022年11月8日",如 "11/8/22"。根據(jù)讀者的國(guó)家,這個(gè)數(shù)據(jù)可以用三種不同的方式來(lái)閱讀。
- “November 8, 2022” 或者 MM/DD/YY 來(lái)自美國(guó)
- “August 11, 2022” or DD/MM/YY 來(lái)自歐洲
- “August 22, 2011” or YY/MM/DD 來(lái)自中國(guó)、日本。
這就是國(guó)際化API(或I18n API)來(lái)解決不同語(yǔ)言和地區(qū)的格式問(wèn)題的地方。I18n API是一個(gè)了不起的工具,有多種用途,但這里不會(huì)深入研究,以免使本文過(guò)于冗長(zhǎng)。
如何使用它?
I18n API 使用 locale 標(biāo)識(shí)符來(lái)工作。locales 參數(shù)必須是一個(gè) BCP 47 語(yǔ)言標(biāo)記的字符串,或者是一個(gè)包括多個(gè)語(yǔ)言標(biāo)記的數(shù)組。如果 locales 參數(shù)未提供或者是 undefined,便會(huì)使用運(yùn)行時(shí)默認(rèn)的 locale。
一個(gè) BCP 47 語(yǔ)言標(biāo)記代表了一種語(yǔ)言或者區(qū)域(兩者沒(méi)有很大的區(qū)別)。在其最常見(jiàn)的格式中,它以這樣的順序囊括了這些內(nèi)容:語(yǔ)言代碼,腳本代碼,和國(guó)家代碼,全部由連字符分隔開(kāi)。例如:
- "hi":印地語(yǔ) (primary language)。
- "de-AT": 在奧地利使用的德語(yǔ) (primary language with country code)。
- "zh-Hans-CN":在中國(guó)使用的簡(jiǎn)體中文 (primary language with script and country codes)。
更準(zhǔn)確地說(shuō),I18n API提供了一個(gè)Intl對(duì)象,它提供了精確的字符串對(duì)比、數(shù)字格式化,和日期時(shí)間格式化。Collator,NumberFormat 和 DateTimeFormat 對(duì)象的構(gòu)造函數(shù)是 Intl 對(duì)象的屬性。本頁(yè)文檔內(nèi)容包括了這些屬性,以及國(guó)際化使用的構(gòu)造器和其他語(yǔ)言的方法等常見(jiàn)的功能。
Intl.Collator
collators 的構(gòu)造函數(shù),用于啟用對(duì)語(yǔ)言敏感的字符串比較的對(duì)象。
Intl.DateTimeFormat
用于啟用語(yǔ)言敏感的日期和時(shí)間格式的對(duì)象的構(gòu)造函數(shù)。
Intl.ListFormat
啟用對(duì)語(yǔ)言敏感的列表格式化的對(duì)象的構(gòu)造函數(shù)。
Intl.NumberFormat
用于啟用語(yǔ)言敏感數(shù)字格式的對(duì)象的構(gòu)造函數(shù)。
Intl.PluralRules
用于啟用多種敏感格式和多種語(yǔ)言語(yǔ)言規(guī)則的對(duì)象的構(gòu)造函數(shù)。
Intl.RelativeTimeFormat
用于啟用語(yǔ)言敏感的相對(duì)時(shí)間格式化的對(duì)象的構(gòu)造函數(shù)。
在我們的例子中,我們重點(diǎn)關(guān)注 Intl.DateTimeFormat() 構(gòu)造函數(shù),以根據(jù)用戶(hù)的區(qū)域設(shè)置來(lái)格式化報(bào)價(jià)的 dateAdded 屬性。Intl.DateTimeFormat() 構(gòu)造函數(shù)需要兩個(gè)參數(shù):定義日期格式化慣例的 locale 字符串和用于自定義日期格式的 options 對(duì)象。
創(chuàng)建的 Intl.DateTimeFormat() 對(duì)象有一個(gè) format() 方法,它需要兩個(gè)參數(shù):我們要格式化的Date對(duì)象和用于自定義如何顯示格式化日期的 options 對(duì)象。
const logDate = (locale) => {
const newDate = new Date("2022-10-24"); // YY/MM/DD
const dateTime = new Intl.DateTimeFormat(locale, {timeZone: "UTC"});
const formatedDate = dateTime.format(newDate);
console.log(formatedDate);
};
logDate("en-US"); // 10/24/2022
logDate("de-DE"); // 24.10.2022
logDate("zh-TW"); // 2022/10/24
dateTime.format() 根據(jù)當(dāng)?shù)氐娜掌诟袷郊s定改變?nèi)掌凇N覀兛梢允褂胣avigator.language全局屬性在報(bào)價(jià)單的日期上實(shí)現(xiàn)這一行為,該全局屬性持有用戶(hù)的首選區(qū)域設(shè)置。為此,我們將創(chuàng)建一個(gè)新的函數(shù),接收一個(gè)日期字符串(YYYY-MM-DD格式),并根據(jù)用戶(hù)的locale返回格式化的日期。
const formatDate = (dateString) => {
const date = new Date(dateString);
const locale = navigator.language;
const dateTimeFormat = new Intl.DateTimeFormat(locale, {timeZone: "UTC"});
return dateTimeFormat.format(date);
};
代碼部署后可能存在的BUG沒(méi)法實(shí)時(shí)知道,事后為了解決這些BUG,花了大量的時(shí)間進(jìn)行l(wèi)og 調(diào)試,這邊順便給大家推薦一個(gè)好用的BUG監(jiān)控工具 Fundebug。
原文:https://www.smashingmagazine.com/2022/09/javascript-api-guide/