一、概述
在此 Codelab 中,您將學習Firebase的一些基礎知識來創建交互式 Web 應用程序。您將使用多個 Firebase 產品構建活動 RSVP 和留言簿聊天應用。
你會學到什麼
- 使用 Firebase 身份驗證和 FirebaseUI 對用戶進行身份驗證。
- 使用 Cloud Firestore 同步數據。
- 編寫 Firebase 安全規則以保護數據庫。
你需要什麼
- 您選擇的瀏覽器,例如 Chrome。
- 訪問stackblitz.com (無需帳戶或登錄)。
- Google 帳戶,例如 gmail 帳戶。我們建議您使用已用於 GitHub 帳戶的電子郵件帳戶。這允許您使用 StackBlitz 中的高級功能。
- Codelab 的示例代碼。有關如何獲取代碼,請參閱下一步。
2.獲取起始碼
在此 Codelab 中,您將使用StackBlitz構建一個應用,StackBlitz 是一個集成了多個 Firebase 工作流的在線編輯器。 Stackblitz 不需要軟件安裝或特殊的 StackBlitz 帳戶。
StackBlitz 可讓您與他人共享項目。擁有您的 StackBlitz 項目 URL 的其他人可以查看您的代碼並派生您的項目,但他們無法編輯您的 StackBlitz 項目。
- 轉到此 URL 獲取起始代碼: https ://stackblitz.com/edit/firebase-gtk-web-start
- 在 StackBlitz 頁面頂部,單擊Fork :
您現在擁有作為您自己的 StackBlitz 項目的起始代碼的副本,它具有唯一的名稱和唯一的 URL。您的所有文件和更改都保存在此 StackBlitz 項目中。
3.編輯活動信息
此 Codelab 的起始材料為 Web 應用程序提供了一些結構,包括一些樣式表和幾個用於應用程序的 HTML 容器。稍後在本 Codelab 中,您會將這些容器連接到 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 控制台中,點擊Add Project (或Create a project ),然後將您的 Firebase 項目命名為Firebase-Web-Codelab 。
- 單擊項目創建選項。如果出現提示,請接受 Firebase 條款。在 Google Analytics(分析)屏幕上,單擊“不啟用”,因為您不會為此應用程序使用 Analytics。
要詳細了解 Firebase 項目,請參閱了解 Firebase 項目。
在控制台中啟用和設置 Firebase 產品
您正在構建的應用使用了多個可用於網絡應用的 Firebase 產品:
- Firebase 身份驗證和Firebase 用戶界面可讓您的用戶輕鬆登錄您的應用。
- Cloud Firestore將結構化數據保存在雲端,並在數據更改時獲得即時通知。
- Firebase 安全規則來保護您的數據庫。
其中一些產品需要特殊配置或需要使用 Firebase 控制台啟用。
為 Firebase 身份驗證啟用電子郵件登錄
要允許用戶登錄 Web 應用,您將為此 Codelab 使用電子郵件/密碼登錄方法:
- 在 Firebase 控制台的左側面板中,單擊Build > Authentication 。然後單擊開始。您現在位於身份驗證儀表板中,您可以在其中查看註冊用戶、配置登錄提供程序和管理設置。
- 選擇登錄方法選項卡(或單擊此處直接轉到該選項卡)。
- 單擊提供商選項中的電子郵件/密碼,將開關切換到啟用,然後單擊保存。
設置 Cloud Firestore
該網絡應用使用Cloud Firestore來保存聊天消息並接收新的聊天消息。
以下是設置 Cloud Firestore 的方法:
- 在 Firebase 控制台的左側面板中,點擊Build > Firestore Database 。然後單擊創建數據庫。
- 單擊創建數據庫。
- 選擇在測試模式下啟動選項。閱讀有關安全規則的免責聲明。測試模式確保您可以在開發過程中自由寫入數據庫。單擊下一步。
- 選擇數據庫的位置(您可以使用默認位置)。但請注意,此位置以後無法更改。
- 單擊完成。
5. 添加並配置 Firebase
現在您已經創建了 Firebase 項目並啟用了一些服務,您需要告訴代碼您要使用 Firebase,以及要使用哪個 Firebase 項目。
添加 Firebase 庫
要讓您的應用使用 Firebase,您需要將 Firebase 庫添加到應用中。有多種方法可以做到這一點,如Firebase 文檔中所述。例如,您可以從 Google 的 CDN 添加庫,或者您可以使用 npm 在本地安裝它們,然後在使用 Browserify 時將它們打包到您的應用程序中。
StackBlitz 提供自動捆綁,因此您可以使用 import 語句添加 Firebase 庫。您將使用庫的模塊化 (v9) 版本,這有助於通過稱為“搖樹”的過程減小網頁的整體大小。您可以在文檔中了解有關模塊化 SDK 的更多信息。
要構建此應用,您需要使用 Firebase Authentication、FirebaseUI 和 Cloud Firestore 庫。對於此 Codelab, 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 控制台,點擊左上角的項目概覽,導航到項目的概覽頁面。
- 在項目概覽頁面的中心,單擊 Web 圖標
創建一個新的 Firebase 網絡應用。
- 使用暱稱Web App註冊應用程序。
- 對於此 Codelab,請勿選中Also setup Firebase Hosting for this app旁邊的框。您現在將使用 StackBlitz 的預覽窗格。
- 點擊註冊應用。
- 將Firebase 配置對象複製到剪貼板。
- 點擊Continue to console 。將 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.appspot.com", messagingSenderId: "random-unique-string", appId: "random-unique-string", }; // Initialize Firebase initializeApp(firebaseConfig);
6.添加用戶登錄(RSVP)
現在您已將 Firebase 添加到應用程序中,您可以設置一個 RSVP 按鈕,以使用Firebase 身份驗證註冊人員。
使用電子郵件登錄和 FirebaseUI 對您的用戶進行身份驗證
您需要一個 RSVP 按鈕來提示用戶使用他們的電子郵件地址登錄。您可以通過將FirebaseUI連接到 RSVP 按鈕來做到這一點。FirebaseUI 是一個庫,可在 Firebase Auth 之上為您提供預構建的 UI。
FirebaseUI 需要做兩件事的配置(請參閱文檔中的選項):
- 告訴 FirebaseUI 您要使用電子郵件/密碼登錄方法。
- 處理成功登錄的回調並返回 false 以避免重定向。您不希望頁面刷新,因為您正在構建單頁 Web 應用程序。
添加代碼以初始化 FirebaseUI Auth
- 在 StackBlitz 中,轉到
index.js
文件。 - 在頂部,找到 firebase
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
之後保存對 auth 對象的引用,如下所示: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
中添加 RSVP 按鈕的 HTML,如下例所示。
請注意使用如下所示的相同id
值,因為對於此 codelab,index.js
文件中已經有這些特定 ID 的掛鉤。
請注意,在index.html
文件中,有一個 IDfirebaseui-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 的預覽窗口中,單擊 RSVP 按鈕以登錄應用程序。
- 對於此 Codelab,您可以使用任何電子郵件地址,甚至是虛假電子郵件地址,因為您沒有為此 Codelab 設置電子郵件驗證步驟。
- 如果您看到一條錯誤消息,指出
auth/operation-not-allowed
或The given sign-in provider is disabled for this Firebase project
,請檢查以確保您在 Firebase 控制台中啟用了電子郵件/密碼作為登錄提供程序。
- 轉到 Firebase 控制台中的身份驗證信息中心。在“用戶”選項卡中,您應該會看到您輸入的用於登錄應用程序的帳戶信息。
將身份驗證狀態添加到 UI
接下來,確保 UI 反映了您已登錄的事實。
您將使用 Firebase 身份驗證狀態偵聽器回調,該回調會在用戶登錄狀態發生變化時收到通知。如果當前有登錄用戶,您的應用會將“RSVP”按鈕切換為“註銷”按鈕。
- 在 StackBlitz 中,轉到
index.js
文件。 - 在頂部,找到
firebase/auth
import 語句,然後添加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> <!-- ... -->
應用預覽
用戶單擊“發送”按鈕將觸發下面的代碼片段。它將消息輸入字段的內容添加到數據庫的guestbook
集合中。具體來說, addDoc
方法將消息內容添加到guestbook
集合中的新文檔(具有自動生成的 ID)中。
- 在 StackBlitz 中,轉到
index.js
文件。 - 在頂部,找到 firebase
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 數據庫。但是,您還不會在實際的 Web 應用程序中看到該消息,因為您仍然需要實現檢索數據。接下來你會這樣做。
但是您可以在 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 控制台的Build部分,點擊Firestore Database ,然後選擇Rules標籤(或點擊此處直接轉到Rules標籤)。
- 您應該會看到以下默認安全規則,以及從今天開始的幾週內的公共訪問時間限制。
識別集合
首先,確定應用程序向其寫入數據的集合。
- 刪除現有的
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
查詢移動到身份驗證偵聽器中。否則會出現權限錯誤,用戶註銷時應用會斷開連接。
- 在 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
變量是否不為null,然後調用函數取消監聽。// ... // 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. 獎勵步驟:練習所學
記錄與會者的 RSVP 狀態
現在,您的應用程序只允許人們在對活動感興趣時開始聊天。此外,您知道某人是否來的唯一方法是他們是否在聊天中發布。讓我們組織起來,讓人們知道有多少人來。
您將添加一個切換來註冊想要參加活動的人,然後收集來的人數。
- 在 StackBlitz 中,轉到
index.html
文件。 - 在
guestbook-container
,添加一組YES和NO按鈕,如下所示:<!-- ... --> <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> <!-- ... -->
應用預覽
接下來,註冊按鈕點擊的監聽器。如果用戶單擊YES ,則使用他們的身份驗證 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 狀態併計算YES的點擊次數。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(); // Subcribe 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 身份驗證
- Firebase 用戶界面
- 雲防火牆
- Firebase 安全規則
下一步
- 想了解更多 Firebase 開發人員工作流程?查看Firebase 模擬器代碼實驗室,了解如何在本地完全測試和運行您的應用。
- 想詳細了解其他 Firebase 產品?也許您想存儲用戶上傳的圖像文件?或者向您的用戶發送通知?查看Firebase 網絡代碼實驗室,了解更深入地了解更多 Firebase 網絡產品的代碼實驗室。
- 想了解有關 Cloud Firestore 的更多信息?也許您想了解子集合和事務?前往Cloud Firestore 網絡代碼實驗室,了解更深入地了解 Cloud Firestore 的代碼實驗室。或查看此YouTube 系列以了解 Cloud Firestore !
學到更多
- Firebase 網站: firebase.google.com
- Firebase YouTube 頻道
進展如何?
我們希望得到您的反饋!請在此處填寫(非常)簡短的表格。