You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Materialize、JS与Firebase v9 FireStore实现收藏按钮功能

实现Materialize卡片收藏到Favorites页面(结合Firebase v9 FireStore)

下面分步骤完成收藏功能,涵盖数据存储、页面跳转和收藏列表渲染:

一、Firebase v9 初始化配置

创建单独的firebase.js文件,配置Firebase并导出所需服务(使用v9模块化语法):

// firebase.js
import { initializeApp } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-app.js";
import { getFirestore, collection, addDoc, getDocs, deleteDoc, doc } from "https://www.gstatic.com/firebasejs/9.22.0/firebase-firestore.js";

// 替换为你的Firebase项目配置
const firebaseConfig = {
  apiKey: "YOUR_API_KEY",
  authDomain: "YOUR_AUTH_DOMAIN",
  projectId: "YOUR_PROJECT_ID",
  storageBucket: "YOUR_STORAGE_BUCKET",
  messagingSenderId: "YOUR_SENDER_ID",
  appId: "YOUR_APP_ID"
};

const app = initializeApp(firebaseConfig);
const db = getFirestore(app);

export { db, collection, addDoc, getDocs, deleteDoc, doc };

在index.html和Favorites.html的</body>前引入该脚本:

<script type="module" src="firebase.js"></script>

二、修改index.html卡片结构并添加收藏逻辑

首先给卡片添加外层容器,方便定位数据:

<!-- 给卡片添加外层容器 -->
<div class="recipe-card card">
  <div class="recipe-img">
    <img src="coffee.jpg" alt="a cup of coffee.">
    <span class="category-name">Mine</span>
  </div>
  <div class="recipe-content">
    <a href="#" class="right btn-floating grey"><i class="material-icons">delete_outline</i></a>
    <h2>Americano
      <a href="#" class="right favorite-btn btn-floating red pulse">
        <i class="material-icons">favorite</i>
      </a>
    </h2>
    <p>Lorem, ipsum dolor sit amet consectetur adipisicing elit...</p>
  </div>
</div>

创建index.js脚本,处理收藏按钮点击事件:

// index.js
import { db, collection, addDoc } from "./firebase.js";

// 获取所有收藏按钮
const favoriteBtns = document.querySelectorAll('.favorite-btn');

favoriteBtns.forEach(btn => {
  btn.addEventListener('click', async (e) => {
    e.preventDefault(); // 阻止默认跳转行为

    // 定位当前卡片容器
    const card = btn.closest('.recipe-card');
    
    // 提取卡片核心数据
    const recipeData = {
      title: card.querySelector('h2').textContent.trim(),
      image: card.querySelector('.recipe-img img').src,
      category: card.querySelector('.category-name').textContent,
      description: card.querySelector('p').textContent.trim()
    };

    try {
      // 将数据存入Firestore的favorites集合
      await addDoc(collection(db, "favorites"), recipeData);
      // 用Materialize Toast提示收藏成功
      M.toast({html: '已添加到收藏'});
      // 延迟1秒跳转到收藏页面
      setTimeout(() => {
        window.location.href = 'Favorites.html';
      }, 1000);
    } catch (e) {
      console.error('添加收藏失败:', e);
      M.toast({html: '收藏失败,请重试'});
    }
  });
});

在index.html中引入该脚本:

<script type="module" src="index.js"></script>
<!-- 别忘了引入Materialize JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>

三、在Favorites.html渲染收藏列表

先编写Favorites.html的基础结构:

<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
  <link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body>
  <div class="container">
    <h1>我的收藏</h1>
    <div id="favorites-container" class="row"></div>
  </div>

  <script type="module" src="firebase.js"></script>
  <script type="module" src="favorites.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
</body>
</html>

创建favorites.js脚本,读取Firestore数据并渲染卡片:

// favorites.js
import { db, collection, getDocs, deleteDoc, doc } from "./firebase.js";

const favoritesContainer = document.getElementById('favorites-container');

// 渲染收藏列表
async function renderFavorites() {
  try {
    const querySnapshot = await getDocs(collection(db, "favorites"));
    favoritesContainer.innerHTML = ''; // 清空容器

    querySnapshot.forEach((doc) => {
      const recipe = doc.data();
      // 创建Materialize卡片元素
      const cardCol = document.createElement('div');
      cardCol.className = 'col s12 m6 l4'; // 响应式布局
      cardCol.innerHTML = `
        <div class="recipe-card card">
          <div class="recipe-img">
            <img src="${recipe.image}" alt="${recipe.title}">
            <span class="category-name">${recipe.category}</span>
          </div>
          <div class="recipe-content">
            <a href="#" class="right btn-floating grey" data-id="${doc.id}">
              <i class="material-icons">delete_outline</i>
            </a>
            <h2>${recipe.title}</h2>
            <p>${recipe.description}</p>
          </div>
        </div>
      `;
      favoritesContainer.appendChild(cardCol);

      // 添加删除收藏功能
      const deleteBtn = cardCol.querySelector('.btn-floating.grey');
      deleteBtn.addEventListener('click', async (e) => {
        e.preventDefault();
        const docId = deleteBtn.getAttribute('data-id');
        await deleteDoc(doc(db, "favorites", docId));
        M.toast({html: '已移除收藏'});
        renderFavorites(); // 重新渲染列表
      });
    });
  } catch (e) {
    console.error('获取收藏失败:', e);
    favoritesContainer.innerHTML = '<p>加载收藏失败,请稍后重试</p>';
  }
}

// 页面加载完成后渲染列表
document.addEventListener('DOMContentLoaded', renderFavorites);

四、关键注意事项

  • Firestore规则设置:开发阶段可将数据库规则设为测试模式,生产环境需结合Firebase Auth限制用户仅能读写自己的收藏:
    rules_version = '2';
    service cloud.firestore {
      match /databases/{database}/documents {
        match /favorites/{doc} {
          allow read, write: if request.auth != null;
        }
      }
    }
    
  • 选择器匹配:确保JS中的DOM选择器与你的HTML结构完全一致,避免数据提取失败。
  • Materialize组件:Toast等组件会自动初始化,若使用其他组件(如模态框)需手动调用M.XXX.init()方法。

内容的提问来源于stack exchange,提问作者Kristen davis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 00:20:39