你不知道的JavaScript APIs
ead>原文連結:https://www.smashingmagazine.com/2022/09/javascript-api-guide/
前言
在本文中,將介紹一些鮮為人知但卻非常有用的API,如:
Page Visibility API
Web Share API
Broadcast Channel API
Internationalization API
我們將一起看看它們是什麼,我們應該在哪裡使用它們,以及如何使用它們。
Page Visibility API
這是一個鮮為人知的 web API,在JS現狀調查中,它的認知度排名倒數第四。它可以讓你知道使用者何時離開了頁面。準確地說,只要頁面的可見性狀態發生變化,無論是使用者最小化、最大化視窗還是切換標籤頁,該API都會觸發一個事件。
在過去,你不得不使用一些噱頭來了解使用者是否切換了標籤頁或最小化了視窗。最流行的方式是使用blur
和focus
瀏覽器事件。使用這些事件會導致類似下面情況的發生:
```jsx window.addEventListener("focus", function () { // User is back on the page // Do Something });
window.addEventListener("blur", function () { // User left the page // Do Something }); ```
前面的程式碼可以工作,但是不符合預期。因為blur
事件是在頁面失去焦點時觸發的,所以當用戶點選搜尋欄、alert
對話方塊、控制檯或視窗邊框時,它就會被觸發。所以,blur
和focus
只告訴我們頁面是否被啟用,但不告訴我們頁面的內容是否被隱藏或顯示。
什麼時候使用
一般來說,我們想要使用Page Visibility API
,是希望用來停止不必要的程式。比如說當用戶沒有看到頁面時,或者執行後臺操作時。具體的場景可以是:
- 當用戶離開頁面時暫停影片、影象旋轉或動畫;
- 如果頁面顯示來自API的實時資料,在使用者離開時暫時停止實時顯示的行為;
- 傳送使用者分析報告。
如何使用
Page Visibility API
帶來了兩個屬性和一個事件,用於訪問頁面可見性狀態:
-
document.hidden
:該屬性是全域性可見並且只讀。儘量避免使用該屬性,因為現在已經被廢棄了。當訪問該屬性時,如果頁面是隱藏狀態則返回true
,如果頁面是可見狀態則返回false
。 -
document.visibilityState
:該屬性是document.hidden
更新後的版本。當訪問該屬性時,會根據頁面的可見性狀態返回四個可能的值:visible
:該頁面是可見的,或者準確地說,它沒有被最小化,也不在另一個標籤頁。hidden
:該頁面不可見,它是最小化的,或者在另一個標籤頁。prerender
:這是一個可見頁面在預渲染時的初始狀態。一個頁面的可見性狀態可以從prerender
開始,然後改變到另一個狀態,但它不能從另一個狀態改變到prerender
。unloaded
:該頁面正在從記憶體中解除安裝。
-
visibilitychange
:這是一個由document
物件提供的事件,當頁面的visibilityState
發生變化時被觸發。
jsx
document.addEventListener("visibilitychange", () => {
if (document.visibilityState === "visible") {
// page is visible
} else {
// page is hidden
}
});
為了瞭解如何使用Page Visibility API
,讓我們用該特性來實現當用戶離開頁面時,暫停影片以及停止從API獲取資源。首先,我將使用vite.js
,它是一個快速啟動新專案的神奇工具:
shell
npm create [email protected] unknown-web-apis
當被要求選擇一個框架時,選擇vanilla
來建立一個vanilla
javascript專案。完成之後,前往新資料夾,安裝必要的npm
包並啟動開發伺服器:
shell
cd unknown-web-apis
npm install
npm run dev
開啟localhost:3000/,你將看到你的Vite專案啟動和執行!
首先,我們直接跳轉到/main.js
檔案並刪除所有樣板程式碼。其次,開啟/index.html
,在id
為#app
的div
標籤內部新增一個video
元素,上面可以新增你想新增的任意影片檔案。這裡我使用了一隻正在跳舞的耀西。
```html
```
回到/main.js
,我們將向document
物件新增一個事件監聽器,用來監聽visibilitychange
事件。然後當頁面顯示或隱藏時,我們可以訪問document.visibilityState
屬性的值。
jsx
document.addEventListener("visibilitychange", () => {
console.log(document.visibilityState);
});
你可以前往頁面的控制檯,當最小化視窗或者切換到另一個標籤頁時,檢視頁面可見性狀態。現在,在事件監聽器內部,我們可以檢查document.visibilityState
屬性,當屬性值為hidden
時暫停影片,當屬性值為visible
時播放影片。當然,我們首先要使用document.querySelector()
選擇video
元素。
```jsx const video = document.querySelector("#video");
document.addEventListener("visibilitychange", () => { if (document.visibilityState === "visible") { video.play(); } else { video.pause(); } }); ```
現在,只要使用者離開頁面,影片就會停止。另一個使用Page Visibility API
的場景是,當用戶沒有檢視頁面時,停止獲取不必要的資源。為了看效果,我們將編寫一個函式不間斷地從quotable.io API獲取隨機引用,並當頁面隱藏時暫停該行為。首先,我們將在/index.html
建立一個新的div
標籤來儲存引用。
```html
```
回到/main.js
,我們使用Fetch API發起對quotable.io
端點https://api.quotable.io/random 的呼叫,然後將結果插入到quote
div中。
```jsx const quote = document.querySelector('#quote');
const getQuote = async () => {
try {
const response = await fetch('https://api.quotable.io/random');
const { content, author, dateAdded } = await response.json();
const parsedQuote = <q>${content}</q> <br> <p>- ${author}</p><br> <p>Added on ${dateAdded}</p>
;
quote.innerHTML = parsedQuote;
} catch (error) {
console.error(error);
}
};
```
讓我們簡單地解釋一下此處發生了什麼。首先我們從DOM中選中了quote
元素。然後宣告getQuote
函式,該函式是一個非同步函式,允許我們使用await
關鍵字進行等待,直到從API中獲取到資料。獲取的資料是JSON格式的,因此我們再次使用await
關鍵字來等待,直到資料被解析為JavaScript物件。
quotable.io
的API為我們提供了content
、author
和dateAdded
等屬性,我們把這些屬性注入並顯示在quote
div中。這樣做是沒問題的,但是引用只會獲取一次,因此我們可以使用setInterval()
每10秒來呼叫一次函式。
```jsx const quote = document.querySelector('#quote');
const getQuote = async () => {
try {
const response = await fetch('https://api.quotable.io/random');
const { content, author, dateAdded } = await response.json();
const parsedQuote = <q>${content}</q> <br> <p>- ${author}</p><br> <p>Added on ${dateAdded}</p>
;
quote.innerHTML = parsedQuote;
} catch (error) {
console.error(error);
}
};
getQuote();
setInterval(getQuote, 10000); ```
如果使用者最小化視窗或者切換標籤頁,該頁面仍然會獲取引用,建立沒有必要的網路載入。為了解決這個問題,在獲取引用之前我們可以檢查當前頁面是否可見。
``jsx
const getQuote = async () => {
if (document.visibilityState === 'visible') {
try {
const response = await fetch('<https://api.quotable.io/random>');
const { content, author, dateAdded } = await response.json();
const parsedQuote =
${content}
- ${author}
Added on ${dateAdded}
`; quote.innerHTML = parsedQuote; } catch (error) { console.error(error); } } };getQuote();
setInterval(getQuote, 10000); ```
現在,我們只會在頁面對使用者可見的情況下獲取引用。
相容性
Web Share API
這是什麼
Web Share API
也是最不為人所知的API之一,但卻非常有用。它可以讓你訪問作業系統的原生分享機制,這對移動端使用者特別有用。有了這個API,你可以分享文字、連結和檔案,而不需要建立你自己的分享機制或使用第三方的分享機制。
什麼時候使用
用途已經不言自明。你可以用它將你的頁面內容分享到社交媒體上,或將其複製到使用者的剪貼簿上。
如何使用
Web Share API
賦予我們兩個介面來訪問使用者的分享系統:
-
navigator.canShare()
:接受你想分享的資料作為引數,並根據其是否可分享,來返回一個布林引數。 -
navigator.share()
:返回一個promise
,如果分享成功的話,該promise
將會resolve
。該介面會呼叫原生分享機制,並接收你想分享的資料作為引數。注意,它只能在使用者按下連結或按鈕時呼叫。也就是說,它需要transient activation(瞬時啟用)。分享資料是一個可以具有以下屬性的物件:url
:要分享的連結text
:要分享的文字title
:要分享的標題files
:表示要分享的File
物件陣列
為了瞭解如何使用該API,我們將回收先前的用例,做一個選項使用Web Sharing API
來分享我們的引用。首先,我們必須在/index.html
新增一個分享按鈕:
```html
```
前往/main.js
從DOM中選擇分享按鈕。然後,建立async
函式來分享想要分享的資料。
```jsx const shareButton = document.querySelector("#share-button");
const shareQuote = async (shareData) => { try { await navigator.share(shareData); } catch (error) { console.error(error); } }; ```
現在,我們可以為shareButton
元素新增click
事件監聽器,以此來呼叫shareQuote
函式。shareData.text
的值會是quote.textContent
屬性,shareData.url
的值會是頁面的URL,也就是location.href
屬性。
```jsx const shareButton = document.querySelector("#share-button");
const shareQuote = async (shareData) => { try { await navigator.share(shareData); } catch (error) { console.error(error); } };
shareButton.addEventListener("click", () => { let shareData = { title: "A Beautiful Quote", text: quote.textContent, url: location.href, };
shareQuote(shareData);
}); ```
現在你可以通過你的原生作業系統與任何人分享你的引用。然而,需要注意的是,Web Share API
只有在上下文安全的情況下才會起作用,也就是說,頁面是通過https://
或wss://
URLs提供的。
相容性
Broadcast Channel API
這是什麼
我想談論的另一個API是Broadcast Channel API
。它允許瀏覽器上下文互相傳送和接收基本資料。瀏覽器上下文是指標籤頁、視窗、iframe
等元素,或任何可以顯示頁面的地方。出於安全考量,瀏覽器上下文之間的通訊是不被允許的,除非它們是同源的並使用Broadcast Channel API
。對於兩個同源的瀏覽器上下文,它們的URL必須有相同的協議(如http/https
)、域(如example.com
)和埠(如:8080
)。
什麼時候使用
Broadcast Channel API
通常用於在不同的標籤頁和視窗之間保持頁面狀態同步,以提高使用者體驗或出於安全原因考慮。它也可以用來知道一個服務在另一個標籤頁或視窗中何時完成。使用場景有:
- 在所有標籤頁上登入或登出使用者。
- 檢測資源何時上傳,並在所有頁面中展示它。
- 指示
service worker
做一些幕後工作。
如何使用
Broadcast Channel API
涉及一個BroadcastChannel
物件,該物件可用於向其他上下文傳送資訊。建構函式只有一個引數:作為識別符號的字串,該識別符號從其他上下文連線到頻道。
jsx
const broadcast = new BroadcastChannel("new_channel");
一旦我們在兩個上下文中建立了具有相同識別符號的BroadcastChannel
物件,這個新的BroadcastChannel
物件將有兩個可用的方法來開始進行通訊:
-
BroadcastChannel.postMessage()
:在所有連線的上下文中傳送訊息。它接受任意型別的物件作為其唯一的引數,因此你可以傳送各種各樣的資料。jsx broadcast.postMessage("Example message");
-
BroadcastChannel.close()
:關閉通道,向瀏覽器表明它不會再收到任何資訊,這樣它就可以把這些資訊收集到垃圾回收中。
為了接受資訊,BroadcastChannel
有一個message
事件,我們可以使用addEventListener
或其onmessage
屬性來監聽。message
事件有一個data
屬性,包含傳送的資料和其他屬性,以識別傳送訊息的上下文,如origin
、lastEventId
、source
和ports
。
jsx
broadcast.onmessage = ({data, origin}) => {
console.log(`${origin} says ${data}`);
};
讓我們看看如何通過使用先前的例子來使用Broadcast Channel API
。我們的目標是製作另一個具有同源的瀏覽器上下文,並在兩個上下文中展示相同的引用。為了做到這一點,我們將建立一個名為new-origin
的新資料夾,裡面有一個新的/index.html
和/main.js
檔案。
/new-origin/index.html
將是一個新的HTML模板,裡面有一個#quote
div:
```html
在/new-origin/main.js
檔案中,我們將建立一個新的broadcast channel
,並從DOM中選擇#quote
元素:
jsx
const broadcast = new BroadcastChannel("quote_channel");
const quote = document.querySelector("#quote");
在先前的/main.js
檔案中,我們將建立新的BroadcastChannel
物件,並連線到"quote_channel"
。我們還將修改getQuote
函式,將引用作為訊息傳送到其他上下文。
```jsx const broadcast = new BroadcastChannel("quote_channel");
//...
const getQuote = async () => {
try {
const response = await fetch("https://api.quotable.io/random");
const {content, author, dateAdded} = await response.json();
const parsedQuote = <q>${content}</q> <br> <p>- ${author}</p><br> <p>Added on ${dateAdded}</p>
;
quote.innerHTML = parsedQuote;
broadcast.postMessage(parsedQuote);
} catch (error) {
console.error(error);
}
};
```
回到/new-origin/main.js
檔案,我們將監聽message
事件並在每次傳送新的引用時改變quote.innerHTML
。
```jsx const broadcast = new BroadcastChannel("quote_channel"); const quote = document.querySelector("#quote");
broadcast.onmessage = ({data}) => { quote.innerHTML = data; }; ```
現在你可以看到http://localhost:3000/new-origin/
中的引用是如何變化為http://localhost:3000
中的引用的。你也可以注意到,當http://localhost:3000
標籤被隱藏時,引用並沒有改變,因為它只在其頁面可見性狀態為可見時才會去獲取引用。
相容性
Internationalization API
這是什麼
在開發一個網頁或應用程式時,需要將其內容翻譯成其他語言以覆蓋更廣泛的受眾是非常常見的。然而,僅僅將你的網頁文字翻譯成你所需要的任何語言,並不足以使你的內容對講該語言的人可用,因為像日期、數字、單位等東西在不同國家是不同的,可能會給你的使用者帶來困惑。
我們假設你想在你的網頁上展示日期"2022年11月8日",就像"11/8/22"。根據讀者所在的國家,這些資料可以用三種不同的方式來閱讀:
- "11/8/2022"或美國使用者的MM/DD/YY。
- "8/11/2022"或歐洲和拉美使用者的DD/MM/YY。
- "2011/8/22"或日本、中國和加拿大使用者的YY/MM/DD。
這就是Internationalization API
(或I18n API
)來解決不同語言和地區的格式問題的地方。I18n API
是一個了不起的工具,有多種用途,但我們不會深入研究,以免使本文過於複雜。
如何使用
I18n API
使用locale
識別符號來起作用。locale
識別符號是一個字串,用來表示使用者的語言、城市、地區、方言以及其他偏好。準確的說,locale
識別符號是一個字串,由連字元分隔的子標籤組成。子標籤代表了使用者偏好,比如語言、國家、地區或文字,並以以下方式格式化:
"zh"
:中文(語言);"zh-Hant"
:用繁體字(文字)書寫的中文(語言);"zh-Hant-TW"
:在臺灣(地區)使用的繁體字(文字)書寫的中文(語言)。
還有更多的子標籤來解決更多使用者的偏好(如果你想了解更多,你可以檢視RFC對語言標籤的定義),但簡而言之,I18n API
使用這些locale
識別符號來知道如何格式化所有語言敏感的資料。
更確切地說,I18n API
提供了一個Intl
物件,它帶來了一堆專門的建構函式來處理對語言敏感的資料。在我看來,一些對國際化最有用的Intl
建構函式是:
Intl.DateTimeFormat()
:用於格式化日期和時間。Intl.DisplayNames()
:用於格式化語言、地區和文字顯示名字。Intl.Locale()
:用於構建和操作locale
識別符號標籤。Intl.NumberFormat()
:用於格式化數字。Intl.RelativeTimeFormat()
:用於格式化相對時間描述。
在我們的例子中,我們將重點關注Intl.DateTimeFormat()
建構函式,以根據使用者的區域設定來格式化引用的dateAdded
屬性。Intl.DateTimeFormat()
建構函式接收兩個引數:定義日期格式約定的locale
字串和用於自定義日期格式的options
物件。
建立的Intl.DateTimeFormat()
物件有一個format()
方法,它接收兩個引數:我們要格式化的Date
物件和用於自定義如何顯示格式化日期的options
物件。
```jsx 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 ```
注意:在Intl.DateTimeFormat
建構函式的options
引數中,我們將timeZone
屬性設定為"UTC"
,這樣日期就不會被格式化為使用者的當地時間。在我的例子中,沒有timeZone
的選項,日期被解析為 "10/23/2022"。
正如你所看到的,dateTime.format()
根據locale
的日期格式約定改變日期。我們可以使用navigator.language
全域性屬性在引用的日期上實現這一行為,該全域性屬性具有使用者的首選locale
設定。為此,我們將建立一個新的函式,接收一個日期字串(YYYY-MM-DD格式),並根據使用者的locale
返回格式化的日期。
```jsx const formatDate = (dateString) => { const date = new Date(dateString); const locale = navigator.language; const dateTimeFormat = new Intl.DateTimeFormat(locale, {timeZone: "UTC"});
return dateTimeFormat.format(date);
}; ```
我們可以在getQuote()
函式中新增這個函式來解析dateAdded
日期。
jsx
const getQuote = async () => {
if (document.visibilityState === "visible") {
try {
const response = await fetch("<https://api.quotable.io/random>");
const {content, author, dateAdded} = await response.json();
const parsedQuote = `
<q>${content}</q> <br>
<p>- ${author}</p><br>
<p>Added on ${formatDate(dateAdded)}</p>`;
quote.innerHTML = parsedQuote;
broadcast.postMessage(parsedQuote);
} catch (error) {
console.error(error);
}
}
};
有了這個,我們的引用就被本地化為使用者的首選語言了!在我的例子中,我的navigator.language
值是"en"
,所以我的日期被格式化為MM/DD/YY。
相容性
總結
讀完這篇文章後,你現在可以靈活地瞭解這些API的存在以及如何使用它們。儘管它們在JS現狀調查中的認知度排名最後,但它們非常有用,知道如何使用它們肯定會提高你的開發經驗。這些強大的API並不為人所知,這意味著還有一些你我都不知道的有用的API,所以現在是探索並找到那個可以簡化你的程式碼,併為你節省大量開發時間的API的最佳時機。
以上就是本文的所有內容,如有對你有所幫助,歡迎點贊收藏轉發~