1. 總覽
在本程式碼研究室中,您將學習一些 Firebase 的基本概念,以便建立互動式網頁應用程式。您將使用多項 Firebase 產品建構活動回覆和留言板聊天應用程式。
課程內容
- 使用 Firebase 驗證和 FirebaseUI 驗證使用者。
- 使用 Cloud Firestore 同步處理資料。
- 編寫 Firebase 安全性規則,保護資料庫安全。
事前準備
- 你偏好的瀏覽器,例如 Chrome。
- stackblitz.com 存取權 (無需帳戶或登入)。
- 擁有 Google 帳戶,例如 Gmail 帳戶。建議您使用已用於 GitHub 帳戶的電子郵件地址。這樣一來,您就能在 StackBlitz 中使用進階功能。
- 程式碼研究室的程式碼範例。請參閱下一個步驟,瞭解如何取得程式碼。
2. 取得範例程式碼
在本程式碼研究室中,您將使用 StackBlitz 建構應用程式,這是整合了多個 Firebase 工作流程的線上編輯器。您不需要安裝軟體或建立特殊的 StackBlitz 帳戶,即可使用 Stackblitz。
您可以透過 StackBlitz 與他人共用專案。其他人只要有您的 StackBlitz 專案網址,就能查看您的程式碼並分支您的專案,但無法編輯您的 StackBlitz 專案。
- 前往這個網址取得啟動程式碼:https://stackblitz.com/edit/firebase-gtk-web-start
- 按一下 StackBlitz 頁面頂端的「Fork」:
您現在擁有起始程式碼的副本,也就是您自己的 StackBlitz 專案,該專案具有專屬名稱和專屬網址。所有檔案和變更都會儲存在這個 StackBlitz 專案中。
3. 編輯事件資訊
這個程式碼研究室的起始素材會為網頁應用程式提供一些結構,包括一些樣式表單和應用程式的幾個 HTML 容器。在本程式碼研究室的後續內容中,您將連結這些容器至 Firebase。
首先,讓我們進一步瞭解 StackBlitz 介面。
- 在 StackBlitz 中開啟
index.html
檔案。 - 找出
event-details-container
和description-container
,然後嘗試編輯部分事件詳細資料。
編輯文字時,StackBlitz 會自動重新整理頁面,並顯示新的事件詳細資料。好,對吧?
<!-- ... -->
<div id="app">
<img src="..." />
<section id="event-details-container">
<h1>Firebase Meetup</h1>
<p><i class="material-icons">calendar_today</i> October 30</p>
<p><i class="material-icons">location_city</i> San Francisco</p>
</section>
<hr>
<section id="firebaseui-auth-container"></section>
<section id="description-container">
<h2>What we'll be doing</h2>
<p>Join us for a day full of Firebase Workshops and Pizza!</p>
</section>
</div>
<!-- ... -->
應用程式的預覽畫面應如下所示:
應用程式預覽
4. 建立及設定 Firebase 專案
顯示活動資訊對住客來說很有幫助,但只顯示活動資訊對任何人來說都沒什麼用處。讓我們為這個應用程式新增一些動態功能。為此,您必須將 Firebase 連結至應用程式。如要開始使用 Firebase,您必須建立及設定 Firebase 專案。
建立 Firebase 專案
- 登入 Firebase。
- 在 Firebase 控制台中,按一下「新增專案」 (或「建立專案」),然後將 Firebase 專案命名為「Firebase-Web-Codelab」。
- 點選專案建立選項。當系統顯示提示時,請接受 Firebase 條款。在 Google Analytics 畫面上,點選「不啟用」,因為這個應用程式不會用到 Analytics。
如要進一步瞭解 Firebase 專案,請參閱「瞭解 Firebase 專案」一文。
在控制台中啟用及設定 Firebase 產品
您建構的應用程式會使用幾項 Firebase 產品,這些產品都可用於網頁應用程式:
- Firebase 驗證和 Firebase UI:可讓使用者輕鬆登入您的應用程式。
- Cloud Firestore:在雲端儲存結構化資料,並在資料變更時立即收到通知。
- Firebase 安全性規則:可保護資料庫的安全。
部分產品需要特殊設定或透過 Firebase 控制台啟用。
為 Firebase 驗證啟用電子郵件登入功能
為了讓使用者登入網頁應用程式,請在本程式碼研究室中使用「電子郵件/密碼」登入方式:
- 在 Firebase 控制台左側面板中,依序按一下「建構」 >「驗證」。然後按一下「開始使用」。您現在已進入驗證資訊主頁,可以查看註冊的使用者、設定登入提供者,以及管理設定。
- 選取「登入方式」分頁標籤 (或按這裡直接前往該分頁)。
- 在供應商選項中按一下「電子郵件/密碼」,將切換鈕切換至「啟用」,然後按一下「儲存」。
設定 Cloud Firestore
這個網頁應用程式會使用 Cloud Firestore 儲存即時通訊訊息,並接收新的即時通訊訊息。
以下說明如何在 Firebase 專案中設定 Cloud Firestore:
5. 新增及設定 Firebase
Firebase 專案已建立,部分服務也已啟用,現在您需要告訴程式碼要使用 Firebase,以及要使用的 Firebase 專案。
新增 Firebase 程式庫
如要讓應用程式使用 Firebase,您必須將 Firebase 程式庫新增至應用程式。如需詳細資訊,請參閱 Firebase 說明文件。舉例來說,您可以從 Google 的 CDN 新增程式庫,也可以使用 npm 在本機安裝程式庫,然後在應用程式中打包 (如果您使用 Browserify)。
StackBlitz 提供自動封裝功能,因此您可以使用匯入陳述式新增 Firebase 程式庫。您將使用模組化 (v9) 版本的程式庫,透過稱為「樹狀圖搖動」的程序,有助於縮減網頁的整體大小。如要進一步瞭解模組 SDK,請參閱說明文件。
如要建構這個應用程式,您必須使用 Firebase 驗證、FirebaseUI 和 Cloud Firestore 程式庫。在本程式碼研究室中,我們已在 index.js
檔案頂端加入以下匯入陳述式,並會在後續步驟中從各個 Firebase 程式庫匯入更多方法:
// Import stylesheets
import './style.css';
// Firebase App (the core Firebase SDK) is always required
import { initializeApp } from 'firebase/app';
// Add the Firebase products and methods that you want to use
import {} from 'firebase/auth';
import {} from 'firebase/firestore';
import * as firebaseui from 'firebaseui';
將 Firebase 網頁應用程式新增至 Firebase 專案
- 回到 Firebase 控制台,按一下左上方的「專案總覽」,前往專案總覽頁面。
- 在專案總覽頁面的中央,按一下網頁圖示 建立新的 Firebase 網頁應用程式。
- 使用「網頁應用程式」做為應用程式別名註冊應用程式。
- 在本程式碼研究室中,請勿勾選「Also set up Firebase Hosting for this app」旁的方塊。您目前會使用 StackBlitz 的預覽窗格。
- 按一下「註冊應用程式」。
- 將 Firebase 設定物件複製到剪貼簿。
- 按一下「繼續前往控制台」。將 Firebase 設定物件新增至應用程式:
- 回到 StackBlitz,前往
index.js
檔案。 - 找出
Add Firebase project configuration object here
註解行,然後將設定程式碼片段貼到註解下方。 - 新增
initializeApp
函式呼叫,以便使用專屬的 Firebase 專案設定來設定 Firebase。// ... // Add Firebase project configuration object here const firebaseConfig = { apiKey: "random-unique-string", authDomain: "your-projectId.firebaseapp.com", databaseURL: "https://your-projectId.firebaseio.com", projectId: "your-projectId", storageBucket: "your-projectId.firebasestorage.app", messagingSenderId: "random-unique-string", appId: "random-unique-string", }; // Initialize Firebase initializeApp(firebaseConfig);
6. 新增使用者登入 (回覆邀請)
在應用程式中加入 Firebase 後,您可以設定回覆按鈕,讓使用者透過 Firebase 驗證功能註冊。
使用電子郵件登入功能和 FirebaseUI 驗證使用者
您需要回覆按鈕,提示使用者以電子郵件地址登入。您可以將 FirebaseUI 連結至 RSVP 按鈕。FirebaseUI 是可在 Firebase Auth 上提供預先建構 UI 的程式庫。
FirebaseUI 需要設定 (請參閱說明文件中的選項),以便執行以下兩項操作:
- 告訴 FirebaseUI 您要使用「電子郵件/密碼」登入方式。
- 處理成功登入的回呼,並傳回 false 以避免重新導向。您不希望頁面重新整理,因為您正在建構單頁面網頁應用程式。
新增用於初始化 FirebaseUI Auth 的程式碼
- 在 StackBlitz 中,前往
index.js
檔案。 - 在頂端找出
firebase/auth
匯入陳述式,然後新增getAuth
和EmailAuthProvider
,如下所示:// ... // Add the Firebase products and methods that you want to use import { getAuth, EmailAuthProvider } from 'firebase/auth'; import {} from 'firebase/firestore';
- 在
initializeApp
後立即儲存對驗證物件的參照,如下所示:initializeApp(firebaseConfig); auth = getAuth();
- 請注意,起始程式碼中已提供 FirebaseUI 設定。已設定為使用電子郵件驗證服務供應器。
- 在
index.js
的main()
函式底部,新增 FirebaseUI 初始化陳述式,如下所示:async function main() { // ... // Initialize the FirebaseUI widget using Firebase const ui = new firebaseui.auth.AuthUI(auth); } main();
在 HTML 中新增 RSVP 按鈕
- 在 StackBlitz 中,前往
index.html
檔案。 - 在
event-details-container
中加入回覆按鈕的 HTML,如以下範例所示。
請務必使用下方所示的id
值,因為在本程式碼研究室中,index.js
檔案中已為這些特定 ID 建立鉤子。
請注意,在index.html
檔案中,有一個 ID 為firebaseui-auth-container
的容器。這是您會傳遞至 FirebaseUI 的 ID,用於保存登入資訊。
應用程式預覽<!-- ... --> <section id="event-details-container"> <!-- ... --> <!-- ADD THE RSVP BUTTON HERE --> <button id="startRsvp">RSVP</button> </section> <hr> <section id="firebaseui-auth-container"></section> <!-- ... -->
- 在 RSVP 按鈕上設定事件監聽器,並呼叫 FirebaseUI 啟動函式。這會告訴 FirebaseUI,您想查看登入視窗。
在index.js
的main()
函式底部加入下列程式碼:async function main() { // ... // Listen to RSVP button clicks startRsvpButton.addEventListener("click", () => { ui.start("#firebaseui-auth-container", uiConfig); }); } main();
測試登入應用程式
- 在 StackBlitz 的預覽視窗中,按一下「回覆」按鈕登入應用程式。
- 在本程式碼研究室中,您可以使用任何電子郵件地址,甚至是假的電子郵件地址,因為您不會為本程式碼研究室設定電子郵件驗證步驟。
- 如果您看到顯示
auth/operation-not-allowed
或The given sign-in provider is disabled for this Firebase project
的錯誤訊息,請確認您已在 Firebase 控制台中啟用「電子郵件/密碼」做為登入提供者。
- 前往 Firebase 主控台的「驗證」資訊主頁。在「使用者」分頁中,您應該會看到登入應用程式時輸入的帳戶資訊。
在 UI 中新增驗證狀態
接著,請確認 UI 能反映您已登入的事實。
您將使用 Firebase 驗證狀態事件監聽器回呼,當使用者的登入狀態發生變更時,系統會通知您。如果目前有登入的使用者,應用程式會將「回覆」按鈕切換為「登出」按鈕。
- 在 StackBlitz 中,前往
index.js
檔案。 - 在頂端找出
firebase/auth
匯入陳述式,然後新增signOut
和onAuthStateChanged
,如下所示:// ... // Add the Firebase products and methods that you want to use import { getAuth, EmailAuthProvider, signOut, onAuthStateChanged } from 'firebase/auth'; import {} from 'firebase/firestore';
- 在
main()
函式的底部加入下列程式碼:async function main() { // ... // Listen to the current Auth state onAuthStateChanged(auth, user => { if (user) { startRsvpButton.textContent = 'LOGOUT'; } else { startRsvpButton.textContent = 'RSVP'; } }); } main();
- 在按鈕事件監聽器中,檢查是否有目前的使用者,並將他們登出。如要這麼做,請將目前的
startRsvpButton.addEventListener
替換為以下內容:// ... // Called when the user clicks the RSVP button startRsvpButton.addEventListener('click', () => { if (auth.currentUser) { // User is signed in; allows user to sign out signOut(auth); } else { // No user is signed in; allows user to sign in ui.start('#firebaseui-auth-container', uiConfig); } });
現在,應用程式中的按鈕應顯示「LOGOUT」,點選後應會切換回「RSVP」。
應用程式預覽
7. 將訊息寫入 Cloud Firestore
雖然知道使用者會前來是件好事,但我們也希望能讓訪客在應用程式中執行其他操作。如果他們可以在留言板中留下訊息,那就太棒了!他們可以分享為何期待參加活動,或是想認識哪些人。
如要儲存使用者在應用程式中輸入的即時通訊訊息,您可以使用 Cloud Firestore。
資料模型
Cloud Firestore 是 NoSQL 資料庫,儲存在資料庫中的資料會分成集合、文件、欄位和子集合。您將每則聊天訊息儲存為文件,並放入名為 guestbook
的頂層集合中。
將訊息新增至 Firestore
在本節中,您將新增功能,讓使用者將新訊息寫入資料庫。首先,您要為 UI 元素 (訊息欄位和傳送按鈕) 新增 HTML。接著,您可以新增連結這些元素至資料庫的程式碼。
如要新增訊息欄位和傳送按鈕的 UI 元素,請按照下列步驟操作:
- 在 StackBlitz 中,前往
index.html
檔案。 - 找出
guestbook-container
,然後加入下列 HTML 來建立包含訊息輸入欄位和傳送按鈕的表單。<!-- ... --> <section id="guestbook-container"> <h2>Discussion</h2> <form id="leave-message"> <label>Leave a message: </label> <input type="text" id="message"> <button type="submit"> <i class="material-icons">send</i> <span>SEND</span> </button> </form> </section> <!-- ... -->
應用程式預覽
使用者按下「SEND」按鈕時,系統會觸發下列程式碼片段。這會將訊息輸入欄位的內容新增至資料庫的 guestbook
集合。具體來說,addDoc
方法會將訊息內容新增至 guestbook
集合中的新文件 (附有自動產生的 ID)。
- 在 StackBlitz 中,前往
index.js
檔案。 - 在頂端找出
firebase/firestore
匯入陳述式,然後新增getFirestore
、addDoc
和collection
,如下所示:// ... // Add the Firebase products and methods that you want to use import { getAuth, EmailAuthProvider, signOut, onAuthStateChanged } from 'firebase/auth'; import { getFirestore, addDoc, collection } from 'firebase/firestore';
- 現在,我們會在
initializeApp
後立即儲存 Firestoredb
物件的參照:initializeApp(firebaseConfig); auth = getAuth(); db = getFirestore();
- 在
main()
函式的最下方加入以下程式碼。
請注意,auth.currentUser.uid
是指 Firebase 驗證服務為所有登入使用者自動產生的不重複 ID。async function main() { // ... // Listen to the form submission form.addEventListener('submit', async e => { // Prevent the default form redirect e.preventDefault(); // Write a new message to the database collection "guestbook" addDoc(collection(db, 'guestbook'), { text: input.value, timestamp: Date.now(), name: auth.currentUser.displayName, userId: auth.currentUser.uid }); // clear message input field input.value = ''; // Return false to avoid redirect return false; }); } main();
只向已登入的使用者顯示留言板
你不希望任何人都能看到來賓的聊天內容。您可以採取的做法之一,就是只允許已登入的使用者查看留言板,以確保聊天的安全性。不過,如果是您自己的應用程式,建議您也使用 Firebase 安全性規則保護資料庫。(後續的程式碼研究室會進一步說明安全性規則)。
- 在 StackBlitz 中,前往
index.js
檔案。 - 編輯
onAuthStateChanged
事件監聽器,以便隱藏及顯示留言板。// ... // Listen to the current Auth state onAuthStateChanged(auth, user => { if (user) { startRsvpButton.textContent = 'LOGOUT'; // Show guestbook to logged-in users guestbookContainer.style.display = 'block'; } else { startRsvpButton.textContent = 'RSVP'; // Hide guestbook for non-logged-in users guestbookContainer.style.display = 'none'; } });
測試傳送訊息
- 確認你已登入應用程式。
- 輸入訊息 (例如「嗨!」),然後按一下「傳送」。
這項動作會將訊息寫入 Cloud Firestore 資料庫。不過,您還無法在實際的網頁應用程式中看到這則訊息,因為您還需要實作資料擷取作業。這是您接下來要完成的工作。
不過,您可以在 Firebase 控制台中看到新加入的訊息。
在 Firebase 控制台的 Firestore 資料庫資訊主頁中,您應該會看到 guestbook
集合,其中包含您新加入的訊息。如果您持續傳送訊息,留言板集合就會包含許多文件,如下所示:
Firebase 控制台
8. 讀取訊息
同步處理訊息
雖然訪客可以將訊息寫入資料庫,但他們目前無法在應用程式中查看這些訊息。
如要顯示訊息,您必須新增會在資料變更時觸發的事件監聽器,然後建立可顯示新訊息的 UI 元素。
您將新增程式碼,用來監聽應用程式中新增的訊息。首先,請在 HTML 中新增一個顯示訊息的部分:
- 在 StackBlitz 中,前往
index.html
檔案。 - 在
guestbook-container
中,新增 ID 為guestbook
的新區段。<!-- ... --> <section id="guestbook-container"> <h2>Discussion</h2> <form><!-- ... --></form> <section id="guestbook"></section> </section> <!-- ... -->
接下來,請註冊監聽器,監聽資料的變更:
- 在 StackBlitz 中,前往
index.js
檔案。 - 在頂端找出
firebase/firestore
匯入陳述式,然後新增query
、orderBy
和onSnapshot
,如下所示:// ... import { getFirestore, addDoc, collection, query, orderBy, onSnapshot } from 'firebase/firestore';
- 在
main()
函式的底部新增以下程式碼,以便循環處理資料庫中的所有文件 (留言板訊息)。如要進一步瞭解這個程式碼的運作方式,請參閱程式碼片段下方的資訊。async function main() { // ... // Create query for messages const q = query(collection(db, 'guestbook'), orderBy('timestamp', 'desc')); onSnapshot(q, snaps => { // Reset page guestbook.innerHTML = ''; // Loop through documents in database snaps.forEach(doc => { // Create an HTML entry for each document and add it to the chat const entry = document.createElement('p'); entry.textContent = doc.data().name + ': ' + doc.data().text; guestbook.appendChild(entry); }); }); } main();
為了監聽資料庫中的訊息,您已使用 collection
函式針對特定集合建立查詢。上述程式碼會監聽 guestbook
集合中的變更,這是聊天訊息的儲存位置。訊息也會依日期排序,使用 orderBy('timestamp', 'desc')
將最新的訊息顯示在頂端。
onSnapshot
函式會採用兩個參數:要使用的查詢和回呼函式。當符合查詢的文件發生任何變更時,系統就會觸發回呼函式。例如刪除、修改或新增訊息。詳情請參閱 Cloud Firestore 說明文件。
測試同步處理訊息
Cloud Firestore 會自動即時同步處理資料,並與訂閱資料庫的用戶端同步處理。
- 您先前在資料庫中建立的訊息應該會顯示在應用程式中。歡迎您編寫新訊息,這些訊息應該會立即顯示。
- 如果在多個視窗或分頁中開啟工作區,系統會即時同步處理分頁中的訊息。
- (選用) 您可以嘗試直接在 Firebase 主控台的「資料庫」部分手動刪除、修改或新增訊息,任何變更都會顯示在 UI 中。
恭喜!您正在應用程式中讀取 Cloud Firestore 文件!
應用程式預覽
9. 設定基本安全性規則
您一開始設定 Cloud Firestore 時,會使用測試模式,也就是說資料庫會開放讀取和寫入作業。不過,您應該只在開發過程的初期階段使用測試模式。最佳做法是,在開發應用程式時為資料庫設定安全性規則。安全性應是應用程式結構和行為的必要元素。
安全性規則可讓您控管資料庫中文件和集合的存取權。您可以使用彈性的規則語法,建立可比對所有寫入作業的規則,包括對整個資料庫的寫入作業,以及對特定文件的作業。
您可以在 Firebase 控制台中編寫 Cloud Firestore 的安全性規則:
- 在 Firebase 控制台的「建構」專區中,按一下「Firestore 資料庫」,然後選取「規則」分頁標籤 (或按一下這裡,直接前往「規則」分頁標籤)。
- 您應該會看到下列預設安全性規則,其中的公開存取時間限制為從今天起算的幾週。
找出集合
首先,請找出應用程式寫入資料的集合。
- 刪除現有的
match /{document=**}
子句,讓規則如下所示:rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { } }
- 在
match /databases/{database}/documents
中,找出要保護的珍藏內容:rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /guestbook/{entry} { // You'll add rules here in the next step. } }
新增安全防護規則
由於您在每份留言板文件中使用驗證 UID 做為欄位,因此可以取得驗證 UID,並驗證任何嘗試寫入文件的使用者是否有相符的驗證 UID。
- 將讀取和寫入規則新增至規則集,如下所示:
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /guestbook/{entry} { allow read: if request.auth.uid != null; allow create: if request.auth.uid == request.resource.data.userId; } } }
- 按一下「發布」即可部署新規則。現在,只有登入的使用者可以閱讀留言板上的訊息 (任何訊息),但您只能使用使用者 ID 建立訊息。我們也不允許編輯或刪除訊息。
新增驗證規則
- 新增資料驗證,確保文件中包含所有預期的欄位:
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /guestbook/{entry} { allow read: if request.auth.uid != null; allow create: if request.auth.uid == request.resource.data.userId && "name" in request.resource.data && "text" in request.resource.data && "timestamp" in request.resource.data; } } }
- 按一下「發布」,即可部署新規則。
重設事件監聽器
由於應用程式現在只允許已驗證的使用者登入,因此您應將留言板 firestore
查詢移至 Authentication 事件監聽器中。否則會發生權限錯誤,且在使用者登出時,應用程式會中斷連線。
- 在 StackBlitz 中,前往
index.js
檔案。 - 將留言板收集
onSnapshot
事件監聽器拉入名為subscribeGuestbook
的新函式。此外,請將onSnapshot
函式的結果指派至guestbookListener
變數。
FirestoreonSnapshot
事件監聽器會傳回取消訂閱函式,您之後可以使用該函式取消快照事件監聽器。// ... // Listen to guestbook updates function subscribeGuestbook() { const q = query(collection(db, 'guestbook'), orderBy('timestamp', 'desc')); guestbookListener = onSnapshot(q, snaps => { // Reset page guestbook.innerHTML = ''; // Loop through documents in database snaps.forEach(doc => { // Create an HTML entry for each document and add it to the chat const entry = document.createElement('p'); entry.textContent = doc.data().name + ': ' + doc.data().text; guestbook.appendChild(entry); }); }); }
- 在下方新增名為
unsubscribeGuestbook
的新函式。檢查guestbookListener
變數是否非空值,然後呼叫函式取消事件監聽器。// ... // Unsubscribe from guestbook updates function unsubscribeGuestbook() { if (guestbookListener != null) { guestbookListener(); guestbookListener = null; } }
最後,將新函式新增至 onAuthStateChanged
回呼。
- 在
if (user)
底部新增subscribeGuestbook()
。 - 在
else
陳述式底部新增unsubscribeGuestbook()
。// ... // Listen to the current Auth state onAuthStateChanged(auth, user => { if (user) { startRsvpButton.textContent = 'LOGOUT'; // Show guestbook to logged-in users guestbookContainer.style.display = 'block'; // Subscribe to the guestbook collection subscribeGuestbook(); } else { startRsvpButton.textContent = 'RSVP'; // Hide guestbook for non-logged-in users guestbookContainer.style.display = 'none'; // Unsubscribe from the guestbook collection unsubscribeGuestbook(); } });
10. 額外步驟:練習所學內容
記錄與會者的出席回覆狀態
目前,您的應用程式只允許使用者在對活動感興趣時開始即時通訊。此外,如果有人在即時通訊中發文,你就會知道對方是否會出席。讓我們來安排一下,讓大家知道有多少人會來。
您將新增切換鈕,讓使用者註冊參加活動,然後收集參與人數。
- 在 StackBlitz 中,前往
index.html
檔案。 - 在
guestbook-container
中,新增一組「是」和「否」按鈕,如下所示:<!-- ... --> <section id="guestbook-container"> <h2>Are you attending?</h2> <button id="rsvp-yes">YES</button> <button id="rsvp-no">NO</button> <h2>Discussion</h2> <!-- ... --> </section> <!-- ... -->
應用程式預覽
接下來,請為按鈕點擊事件註冊監聽器。如果使用者點選「是」,系統會使用其驗證 UID 將回應儲存至資料庫。
- 在 StackBlitz 中,前往
index.js
檔案。 - 在頂端找出
firebase/firestore
匯入陳述式,然後新增doc
、setDoc
和where
,如下所示:// ... // Add the Firebase products and methods that you want to use import { getFirestore, addDoc, collection, query, orderBy, onSnapshot, doc, setDoc, where } from 'firebase/firestore';
- 在
main()
函式的底部加入下列程式碼,以便監聽 RSVP 狀態:async function main() { // ... // Listen to RSVP responses rsvpYes.onclick = async () => { }; rsvpNo.onclick = async () => { }; } main();
- 接著,請建立名為
attendees
的新集合,然後在點選任一 RSVP 按鈕時註冊文件參照。視按下的按鈕而定,將該參照設為true
或false
。
首先,針對rsvpYes
:
接著,針對// ... // Listen to RSVP responses rsvpYes.onclick = async () => { // Get a reference to the user's document in the attendees collection const userRef = doc(db, 'attendees', auth.currentUser.uid); // If they RSVP'd yes, save a document with attendi()ng: true try { await setDoc(userRef, { attending: true }); } catch (e) { console.error(e); } };
rsvpNo
做相同的操作,但值為false
:rsvpNo.onclick = async () => { // Get a reference to the user's document in the attendees collection const userRef = doc(db, 'attendees', auth.currentUser.uid); // If they RSVP'd yes, save a document with attending: true try { await setDoc(userRef, { attending: false }); } catch (e) { console.error(e); } };
更新安全性規則
由於您已設定一些規則,因此透過按鈕新增的新資料會遭到拒絕。
允許新增至 attendees
集合
您必須更新規則,才能新增至 attendees
集合。
- 對於
attendees
集合,由於您使用驗證 UID 做為文件名稱,因此可以擷取該名稱,並驗證提交者的uid
是否與他們正在撰寫的文件相同。您可以允許所有人讀取與會者名單 (因為其中沒有私人資料),但只有建立者可以更新名單。rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { // ... // match /attendees/{userId} { allow read: if true; allow write: if request.auth.uid == userId; } } }
- 按一下「發布」,即可部署新規則。
新增驗證規則
- 新增一些資料驗證規則,確保文件中包含所有預期的欄位:
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { // ... // match /attendees/{userId} { allow read: if true; allow write: if request.auth.uid == userId && "attending" in request.resource.data; } } }
- 別忘了按一下「發布」部署規則!
(選用) 您現在可以查看按下按鈕的結果。前往 Firebase 主控台的 Cloud Firestore 資訊主頁。
讀取出席回覆狀態
您已經記錄了回應,現在讓我們看看誰會來,並在 UI 中顯示。
- 在 StackBlitz 中,前往
index.html
檔案。 - 在
description-container
中,新增 ID 為number-attending
的新元素。<!-- ... --> <section id="description-container"> <!-- ... --> <p id="number-attending"></p> </section> <!-- ... -->
接著,請為 attendees
集合註冊事件監聽器,並計算「YES」回應的數量:
- 在 StackBlitz 中,前往
index.js
檔案。 - 在
main()
函式的底部新增以下程式碼,以便監聽 RSVP 狀態並計算「是」點擊次數。async function main() { // ... // Listen for attendee list const attendingQuery = query( collection(db, 'attendees'), where('attending', '==', true) ); const unsubscribe = onSnapshot(attendingQuery, snap => { const newAttendeeCount = snap.docs.length; numberAttending.innerHTML = newAttendeeCount + ' people going'; }); } main();
最後,我們來醒目顯示對應於目前狀態的按鈕。
- 建立函式,檢查目前驗證 UID 是否在
attendees
集合中含有項目,然後將按鈕類別設為clicked
。// ... // Listen for attendee list function subscribeCurrentRSVP(user) { const ref = doc(db, 'attendees', user.uid); rsvpListener = onSnapshot(ref, doc => { if (doc && doc.data()) { const attendingResponse = doc.data().attending; // Update css classes for buttons if (attendingResponse) { rsvpYes.className = 'clicked'; rsvpNo.className = ''; } else { rsvpYes.className = ''; rsvpNo.className = 'clicked'; } } }); }
- 接著,我們來建立取消訂閱的函式。系統會在使用者登出時使用這個值。
// ... function unsubscribeCurrentRSVP() { if (rsvpListener != null) { rsvpListener(); rsvpListener = null; } rsvpYes.className = ''; rsvpNo.className = ''; }
- 從驗證事件監聽器呼叫函式。
// ... // Listen to the current Auth state // Listen to the current Auth state onAuthStateChanged(auth, user => { if (user) { startRsvpButton.textContent = 'LOGOUT'; // Show guestbook to logged-in users guestbookContainer.style.display = 'block'; // Subscribe to the guestbook collection subscribeGuestbook(); // Subscribe to the user's RSVP subscribeCurrentRSVP(user); } else { startRsvpButton.textContent = 'RSVP'; // Hide guestbook for non-logged-in users guestbookContainer.style.display = 'none' ; // Unsubscribe from the guestbook collection unsubscribeGuestbook(); // Unsubscribe from the guestbook collection unsubscribeCurrentRSVP(); } });
- 嘗試以多位使用者的身分登入,並觀察每次按下「是」按鈕時,計數器的數字會增加。
應用程式預覽
11. 恭喜!
您已使用 Firebase 建構互動式即時網頁應用程式!
涵蓋內容
- Firebase 驗證
- FirebaseUI
- Cloud Firestore
- Firebase 安全性規則
後續步驟
- 想進一步瞭解 Firebase 開發人員工作流程嗎?請參閱 Firebase 模擬器程式碼研究室,瞭解如何在本機完全測試及執行應用程式。
- 想進一步瞭解其他 Firebase 產品嗎?您可能想儲存使用者上傳的圖片檔案。或傳送通知給使用者?歡迎查看 Firebase 網頁程式碼研究室,深入瞭解更多 Firebase 網頁產品。
- 想進一步瞭解 Cloud Firestore 嗎?或許您想瞭解子集合和交易?請前往 Cloud Firestore 網頁程式碼研究室,進一步瞭解 Cloud Firestore。或者,您也可以觀看這個 YouTube 系列影片,瞭解 Cloud Firestore!
瞭解詳情
- Firebase 網站:firebase.google.com
- Firebase YouTube 頻道
結果如何?
歡迎提供意見回饋!請點按這裡,填寫 (非常) 簡短的表單。