了解网页版 Firebase

1. 概述

在本程式码实验室中,您将学习一些基础知识的火力地堡创建交互式Web应用程序。您将使用多个 Firebase 产品构建一个活动 RSVP 和留言簿聊天应用。

59abdefbcc23bbbe.png

你会学到什么

  • 使用 Firebase 身份验证和 FirebaseUI 对用户进行身份验证。
  • 使用 Cloud Firestore 同步数据。
  • 编写 Firebase 安全规则来保护数据库。

你需要什么

  • 您选择的浏览器,例如 Chrome。
  • 访问stackblitz.com (不考虑或登录必要)。
  • Google 帐户,例如 Gmail 帐户。我们推荐您已用于 GitHub 帐户的电子邮件帐户。这允许您使用 StackBlitz 中的高级功能。
  • Codelab 的示例代码。有关如何获取代码,请参阅下一步。

2.获取起始码

在本程式码实验室,您使用的是建立一个应用程序StackBlitz ,有几个火力地堡工作流程集成到它的在线编辑器。 Stackblitz 不需要安装软件或特殊的 StackBlitz 帐户。

StackBlitz 可让您与他人共享项目。其他拥有您的 StackBlitz 项目 URL 的人可以看到您的代码并创建您的项目,但他们无法编辑您的 StackBlitz 项目。

  1. 去这个网址为起点代码: https://stackblitz.com/edit/firebase-gtk-web-start
  2. 在StackBlitz页面的顶部,点击f5135360aef481cc.png

您现在拥有一份起始代码的副本作为您自己的 StackBlitz 项目。因为你没有登录,您的帐户被称为@anonymous ,但该项目具有独特的名称,具有独特的URL一起。您的所有文件和更改都保存在此 StackBlitz 项目中。

3.编辑活动信息

此 Codelab 的起始材料为 Web 应用程序提供了一些结构,包括一些样式表和应用程序的几个 HTML 容器。在本 Codelab 的稍后部分,您会将这些容器连接到 Firebase。

首先,让我们更熟悉 StackBlitz 界面。

  1. 在StackBlitz,打开index.html文件。
  2. 找到event-details-containerdescription-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>

<!-- ... -->

您的应用程序的预览应如下所示:

应用预览

908cc57ce3a5b5fe.png

4. 创建并设置 Firebase 项目

显示活动信息对您的客人来说非常有用,但仅显示活动对任何人来说都不是很有用。让我们为这个应用程序添加一些动态功能。为此,您需要将 Firebase 连接到您的应用。要开始使用 Firebase,您需要创建并设置 Firebase 项目。

创建 Firebase 项目

  1. 登录火力地堡
  2. 在火力地堡控制台,点击添加项目(或创建一个项目),然后命名你的火力地堡火力地堡项目的Web-程式码实验室
    a67c239f8cc7f4b5.png
  3. 单击项目创建选项。如果出现提示,请接受 Firebase 条款。跳过设置 Google Analytics,因为您不会为此应用使用 Analytics。

要了解更多关于火力地堡项目,请参阅了解火力地堡项目

在控制台中启用 Firebase 产品

您正在构建的应用使用了多种可用于网络应用的 Firebase 产品:

  • 火力地堡认证火力UI,很容易让你的用户在你的应用程序签名。
  • 云公司的FireStore保存在云中的结构化数据,并得到即时通知的数据发生变化时。
  • 火力地堡安全规则,以确保您的数据库。

其中一些产品需要特殊配置或需要使用 Firebase 控制台启用。

为 Firebase 身份验证启用电子邮件登录

要允许用户在登录到Web应用程序,你会使用电子邮件/密码登录方法对本程式码实验室:

  1. 在火力地堡控制台,点击左侧面板中生成
  2. 点击身份验证,然后点击登录方法选项卡(或点击这里直接进入到登录方法选项卡)。
  3. 点击登录在供应商列表中的电子邮件/密码,设置启用开关至ON位置,然后点击保存
    4c88427cfd869bee.png

启用 Cloud Firestore

Web应用程序使用云公司的FireStore保存聊天消息和接收新的聊天消息。

启用 Cloud Firestore:

  1. 在火力地堡控制台的Build部分,单击数据库的FireStore。
  2. 单击创建数据库
    3ce19fd6467e51c5.png
  3. 在测试模式选项选择开始。阅读有关安全规则的免责声明。测试模式确保您可以在开发过程中自由写入数据库。单击下一步
    56369cebb9300eb.png
  4. 选择数据库的位置(您可以只使用默认值)。但请注意,此位置以后无法更改。
    32f815f4648c3174.png
  5. 点击完成

5. 添加和配置 Firebase

现在您已经创建了 Firebase 项目并启用了一些服务,您需要告诉代码您要使用 Firebase,以及要使用哪个 Firebase 项目。

添加 Firebase 库

要让您的应用使用 Firebase,您需要将 Firebase 库添加到应用中。有多种方法可以做到这一点,因为在火力地堡的文档中描述。例如,您可以从 Google 的 CDN 添加库,或者您可以使用 npm 在本地安装它们,如果您使用的是 Browserify,则将它们打包到您的应用程序中。

StackBlitz 提供自动捆绑,因此您可以使用 import 语句添加 Firebase 库。您将使用这些库的模块化 (v9) 版本,这有助于通过称为“摇树”的过程减小网页的整体大小。您可以了解更多关于SDK的模块化的文档

要构建此应用,您需要使用 Firebase 身份验证、FirebaseUI 和 Cloud Firestore 库。对于本程式码实验室,以下import语句都已经包括在顶部index.js文件,当我们走,我们将进口来自各火力地堡库的详细方法:

// 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 网络应用添加到项目

  1. 早在火力地堡控制台中,导航到项目的概述页面点击项目概况在上面留下。
  2. 在项目概览页面的中心,单击网络图标b286f3d215e1f578.png创建一个新的 Firebase 网络应用。
    c167e9526fad2825.png
  3. 注册昵称Web应用程序的应用程序。
  4. 对于本程式码实验室,不检查旁边还设置了火力地堡主机为这个应用程序的复选框。您现在将使用 StackBlitz 的预览窗格。
  5. 点击注册应用
    c85ac8aa351e2560.png
  6. 副本火力地堡配置对象到剪贴板。
    ed1e598c6132f734.png
  7. 点击继续安慰

将 Firebase 配置对象添加到您的应用:

  1. 早在StackBlitz,转到index.js文件。
  2. 找到Add Firebase project configuration object here注释行,然后粘贴刚才的评论下方的配置片段。
  3. 添加initializeApp函数调用来设置火力地堡用你独特的火力地堡的项目配置。
    // ...
    // 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)

现在,您已经添加火力地堡的应用程序,你可以设置一个回复按钮,使用注册人火力地堡认证

使用电子邮件登录和 FirebaseUI 对您的用户进行身份验证

您需要一个 RSVP 按钮,提示用户使用他们的电子邮件地址登录。您可以通过挂钩做到这一点FirebaseUI到RSVP button.FirebaseUI是它给你的火力地堡验证顶部的预构建UI库。

FirebaseUI需要配置(请参阅在选项文件做两件事情):

  • 告诉FirebaseUI要使用电子邮件/密码登录方法。
  • 处理成功登录的回调并返回 false 以避免重定向。您不希望页面刷新,因为您正在构建单页 Web 应用程序。

添加用于初始化 FirebaseUI Auth 的代码

  1. 在StackBlitz,转到index.js文件。
  2. 在顶部,找到firebase/auth import语句,再加入getAuthEmailAuthProvider ,像这样:
    // ...
    // Add the Firebase products and methods that you want to use
    import { getAuth, EmailAuthProvider } from 'firebase/auth';
    
    import {} from 'firebase/firestore';
    
  3. 保存到auth对象的权利在经过了参考initializeApp ,像这样:
    initializeApp(firebaseConfig);
    auth = getAuth();
    
  4. 请注意,FirebaseUI 配置已在起始代码中提供。它已经设置为使用电子邮件身份验证提供程序。
  5. 在底部main()函数index.js ,添加FirebaseUI初始化语句,像这样:
    async function main() {
      // ...
    
      // Initialize the FirebaseUI widget using Firebase
      const ui = new firebaseui.auth.AuthUI(auth);
    }
    main();
    
    

向 HTML 添加 RSVP 按钮

  1. 在StackBlitz,转到index.html文件。
  2. 添加的HTML内部的RSVP按钮event-details-container如下面的例子。

    小心使用相同的id值,如下图所示,因为对于本程式码实验室,已经有钩在这些特定ID index.js文件。

    注意,在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>
    <!-- ... -->
    
    应用程序预览
    ab9ad7d61bb7b28c.png
  3. 在 RSVP 按钮上设置侦听器并调用 FirebaseUI 启动函数。这会告诉 FirebaseUI 您想要查看登录窗口。

    下面的代码添加到的底部main()函数index.js
    async function main() {
      // ...
    
      // Listen to RSVP button clicks
      startRsvpButton.addEventListener("click",
       () => {
            ui.start("#firebaseui-auth-container", uiConfig);
      });
    }
    main();
    

测试登录应用程序

  1. 在 StackBlitz 的预览窗口中,单击 RSVP 按钮以登录应用程序。
    • 对于此代码实验室,您可以使用任何电子邮件地址,甚至是虚假电子邮件地址,因为您没有为此代码实验室设置电子邮件验证步骤。
    • 如果你看到一个错误信息,指出auth/operation-not-allowedThe given sign-in provider is disabled for this Firebase project ,检查,以确保您启用电子邮件/密码作为火力地堡控制台登录提供商。
    应用预览
    3024f90b52ad55fe.png
  2. 转至验证仪表盘的火力地堡控制台。在用户选项卡,你应该看到在该应用程序进入到标志的帐户信息。 682fc0eca86a99fc.png

向 UI 添加身份验证状态

接下来,确保 UI 反映您已登录的事实。

您将使用 Firebase 身份验证状态侦听器回调,它会在用户登录状态发生变化时收到通知。如果当前有登录用户,您的应用程序会将“RSVP”按钮切换为“注销”按钮。

  1. 在StackBlitz,转到index.js文件。
  2. 在顶部,找到firebase/auth import语句,再加入signOutonAuthStateChanged ,像这样:
    // ...
    // Add the Firebase products and methods that you want to use
    import {
      getAuth,
      EmailAuthProvider,
      signOut,
      onAuthStateChanged
    } from 'firebase/auth';
    
    import {} from 'firebase/firestore';
    
  3. 在底部添加以下代码main()函数:
    async function main() {
      // ...
    
      // Listen to the current Auth state
      onAuthStateChanged(auth, user => {
        if (user) {
          startRsvpButton.textContent = 'LOGOUT';
        } else {
          startRsvpButton.textContent = 'RSVP';
        }
      });
    }
    main();
    
  4. 在按钮监听器中,检查是否有当前用户并注销。要做到这一点,替换当前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);
      }
    });
    

现在,在您的应用程序的按钮应该显示注销,并单击时,应该切换回RSVP。

应用预览

4c540450924f1607.png

7. 将消息写入 Cloud Firestore

知道用户来了很好,但让我们在应用程序中给客人一些其他的事情。如果他们可以在留言簿中留言怎么办?他们可以分享为什么他们很高兴来到这里或他们希望见到谁。

要存储用户在应用程序写入聊天消息,您将使用云计算公司的FireStore

数据模型

Cloud Firestore 是一个 NoSQL 数据库,存储在数据库中的数据被拆分为集合、文档、字段和子集合。你会聊天的每封邮件存储为称为顶级集合文档guestbook

b447950f9f993789.png

将消息添加到 Firestore

在本节中,您将为用户添加将新消息写入数据库的功能。首先,为 UI 元素(消息字段和发送按钮)添加 HTML。然后,添加将这些元素连接到数据库的代码。

添加消息字段和发送按钮的 UI 元素:

  1. 在StackBlitz,转到index.html文件。
  2. 找到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>
    
    <!-- ... -->
    

应用预览

4a892284443cf73d.png

单击发送按钮的用户将触发下面的代码段。它增加了消息输入字段的内容向guestbook数据库的集合。具体而言, addDoc方法将所述消息内容到一个新的文件(带有自动生成ID)到guestbook集合。

  1. 在StackBlitz,转到index.js文件。
  2. 在顶部,找到firebase/firestore import语句,再加入getFirestoreaddDoc ,并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';
    
  3. 现在,我们可以节省参考公司的FireStore db之后客体的权利initializeApp
    initializeApp(firebaseConfig);
    auth = getAuth();
    db = getFirestore();
    
  4. 在底部main()函数中,添加以下代码。

    需要注意的是auth.currentUser.uid是自动生成的唯一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();
    

仅向登录用户显示留言簿

你不想只是任何人看到客人聊天。您可以为确保聊天安全做的一件事是只允许登录的用户查看留言簿。这就是说,对于自己的应用程序,你会想也保护你的数据库火力地堡的安全规则。 (稍后在代码实验室中有更多关于安全规则的信息。)

  1. 在StackBlitz,转到index.js文件。
  2. 编辑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';
      }
    });
    

测试发送消息

  1. 确保您已登录该应用。
  2. 输入消息,如“嘿!”,然后单击发送

此操作会将消息写入您的 Cloud Firestore 数据库。但是,您还不会在实际的 Web 应用程序中看到该消息,因为您仍然需要实现检索数据。你接下来会这样做。

但是您可以在 Firebase 控制台中看到新添加的消息。

在火力地堡控制台,在数据库仪表板,你应该看到guestbook的收集与新添加的消息。如果您继续发送消息,您的留言簿将包含许多文档,如下所示:

Firebase 控制台

713870af0b3b63c.png

8.阅读消息

同步消息

客人可以将消息写入数据库,但他们还无法在应用程序中看到它们,这真是太好了。

要显示消息,您需要添加在数据更改时触发的侦听器,然后创建一个显示新消息的 UI 元素。

您将添加用于侦听来自应用程序的新添加消息的代码。首先,在 HTML 中添加一个部分以显示消息:

  1. 在StackBlitz,转到index.html文件。
  2. guestbook-container中,添加用的ID的新的部分guestbook
    <!-- ... -->
    
      <section id="guestbook-container">
       <h2>Discussion</h2>
    
       <form><!-- ... --></form>
    
       <section id="guestbook"></section>
    
     </section>
    
    <!-- ... -->
    

接下来,注册侦听对数据所做更改的侦听器:

  1. 在StackBlitz,转到index.js文件。
  2. 在顶部,找到firebase/firestore import语句,再加入queryorderBy ,并onSnapshot ,像这样:
    // ...
    import {
      getFirestore,
      addDoc,
      collection,
      query,
      orderBy,
      onSnapshot
    } from 'firebase/firestore';
    
  3. 在底部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函数有两个参数:查询使用和一个回调函数。当与查询匹配的文档发生任何更改时,将触发回调函数。这可能是因为消息被删除、修改或添加。欲了解更多信息,请参阅云公司的FireStore文档

测试同步消息

Cloud Firestore 会自动、即时地与订阅数据库的客户端同步数据。

  • 您之前在数据库中创建的消息应显示在应用程序中。随意编写新消息;他们应该立即出现。
  • 如果您在多个窗口或选项卡中打开工作区,消息将跨选项卡实时同步。
  • (可选)可以尝试手动删除,修改,或直接在火力地堡控制台的数据库部分添加新的消息;任何更改都应显示在 UI 中。

恭喜!您正在应用中阅读 Cloud Firestore 文档!

应用预览

e30df0a9614bae7d.png

9. 设置基本安全规则

您最初将 Cloud Firestore 设置为使用测试模式,这意味着您的数据库可以读写。但是,您应该只在开发的早期阶段使用测试模式。作为最佳实践,您应该在开发应用程序时为数据库设置安全规则。安全性应该是应用程序结构和行为不可或缺的一部分。

安全规则允许您控制对数据库中文档和集合的访问。灵活的规则语法允许您创建规则,以匹配从对整个数据库的所有写入到对特定文档的操作的任何内容。

您可以在 Firebase 控制台中为 Cloud Firestore 编写安全规则:

  1. 在火力地堡控制台的Build部分,单击数据库的FireStore,然后选择规则选项卡(或点击这里直接进入到规则选项卡)。
  2. 您应该会看到以下默认安全规则,以及有关规则公开的警告。

7767a2d2e64e7275.png

识别集合

首先,确定应用程序写入数据的集合。

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验证监听器里查询。否则会出现权限错误,当用户退出时,应用程序将断开连接。

  1. 拉留言收集onSnapshot监听到一个所谓的新功能subscribeGuestbook 。另外,分配结果onSnapshot功能的guestbookListener变量。

    该公司的FireStore onSnapshot监听器返回的退订功能,你就可以使用以后取消快照听众。
    // ...
    // Listen to guestbook updates
    // 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);
        });
      });
    }
    
  2. 添加一个新功能叫下面unsubscribeGuestbook 。检查是否guestbookListener变量不为空,然后打电话取消监听功能。
    // ...
    // Unsubscribe from guestbook updates
    function unsubscribeGuestbook() {
      if (guestbookListener != null) {
        guestbookListener();
        guestbookListener = null;
      }
    }
    

最后,添加新的功能到onAuthStateChanged回调。

  1. 加入subscribeGuestbook()在底部if (user)
  2. 加入unsubscribeGuestbook()在底部else说法。
    // ...
    // 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. 奖励步骤:练习你学到的东西

记录与会者的回复状态

现在,您的应用只允许人们在对活动感兴趣时开始聊天。此外,您知道某人是否来的唯一方法是他们是否在聊天中发布。让我们组织起来,让人们知道有多少人要来。

您将添加一个开关来注册想要参加活动的人,然后收集来的人数。

  1. 在StackBlitz,转到index.html文件。
  2. 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>
    <!-- ... -->
    

应用预览

73ca99ca35c13ee7.png

接下来,为按钮点击注册监听器。如果用户点击YES,然后利用自己的身份验证UID保存到数据库的响应。

  1. 在StackBlitz,转到index.js文件。
  2. 在顶部,找到firebase/firestore import语句,然后添加docsetDoc ,并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';
    
  3. 在底部main()函数,添加以下代码听RSVP状态:
    async function main() {
      // ...
    
      // Listen to RSVP responses
      rsvpYes.onclick = async () => {
      };
      rsvpNo.onclick = async () => {
      };
    }
    main();
    
    
  4. 创建一个名为新收集attendees ,然后注册一个文件引用,如果被点击或者回复按钮。
  5. 设置参照truefalse取决于被点击了哪个按钮。

    首先, 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集合,因为你使用的认证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 信息中心。

读取 RSVP 状态

现在您已经记录了响应,让我们看看谁来了并在 UI 中反映它。

  1. 在StackBlitz,转到index.html文件。
  2. description-container ,添加一个新的元件用的ID number-attending
    <!-- ... -->
    
     <section id="description-container">
         <!-- ... -->
         <p id="number-attending"></p>
     </section>
    
    <!-- ... -->
    

接下来,注册为听众attendees收集和计算的响应的数量:

  1. 在StackBlitz,转到index.js文件。
  2. 在底部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();
    

最后,让我们突出显示当前状态对应的按钮。

  1. 创建一个函数,检查是否当前的认证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';
          }
        }
      });
    }
    
  2. 另外,让我们制作一个取消订阅的功能。这将在用户注销时使用。
    // ...
    function unsubscribeCurrentRSVP() {
      if (rsvpListener != null) {
        rsvpListener();
        rsvpListener = null;
      }
      rsvpYes.className = '';
      rsvpNo.className = '';
    }
    
  3. 从身份验证侦听器调用函数。
    // ...
    // 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();
        }
      });
    
  4. 尝试登录了多个用户,看到每增加一个YES键点击计数增加。

应用预览

3df607d3e0b3c35.png

11. 恭喜!

您已经使用 Firebase 构建了一个交互式实时 Web 应用程序!

我们涵盖的内容

  • Firebase 身份验证
  • Firebase用户界面
  • 云防火墙
  • Firebase 安全规则

下一步

了解更多

进展如何?

我们希望得到您的反馈!请填写一个(非常)简短的形式在这里