PHP项目怎么实现用户收藏取消?

wen PHP项目 80

本文目录导读:

PHP项目怎么实现用户收藏取消?

  1. 数据库设计
  2. PHP后端实现
  3. 前端实现
  4. CSS样式
  5. 使用示例

在PHP项目中实现用户收藏/取消收藏功能,通常需要以下步骤:

数据库设计

首先创建收藏表:

CREATE TABLE `user_favorites` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL COMMENT '用户ID',
  `item_id` int(11) NOT NULL COMMENT '收藏项ID',
  `item_type` varchar(50) NOT NULL COMMENT '收藏类型(article/product等)',
  `created_at` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `user_item` (`user_id`, `item_id`, `item_type`),
  INDEX `user_id` (`user_id`),
  INDEX `item_id` (`item_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

PHP后端实现

收藏/取消收藏接口

<?php
// favorite.php
class FavoriteController {
    private $db;
    public function __construct($db) {
        $this->db = $db;
    }
    /**
     * 切换收藏状态
     */
    public function toggleFavorite($userId, $itemId, $itemType = 'article') {
        // 检查是否已收藏
        $sql = "SELECT id FROM user_favorites 
                WHERE user_id = ? AND item_id = ? AND item_type = ?";
        $stmt = $this->db->prepare($sql);
        $stmt->execute([$userId, $itemId, $itemType]);
        $result = $stmt->fetch();
        if ($result) {
            // 已收藏,取消收藏
            return $this->removeFavorite($result['id']);
        } else {
            // 未收藏,添加收藏
            return $this->addFavorite($userId, $itemId, $itemType);
        }
    }
    /**
     * 添加收藏
     */
    private function addFavorite($userId, $itemId, $itemType) {
        try {
            $sql = "INSERT INTO user_favorites (user_id, item_id, item_type) 
                    VALUES (?, ?, ?)";
            $stmt = $this->db->prepare($sql);
            $stmt->execute([$userId, $itemId, $itemType]);
            return [
                'success' => true,
                'action' => 'favorited',
                'message' => '收藏成功'
            ];
        } catch (PDOException $e) {
            return [
                'success' => false,
                'message' => '收藏失败:' . $e->getMessage()
            ];
        }
    }
    /**
     * 取消收藏
     */
    private function removeFavorite($favoriteId) {
        try {
            $sql = "DELETE FROM user_favorites WHERE id = ?";
            $stmt = $this->db->prepare($sql);
            $stmt->execute([$favoriteId]);
            return [
                'success' => true,
                'action' => 'unfavorited',
                'message' => '取消收藏成功'
            ];
        } catch (PDOException $e) {
            return [
                'success' => false,
                'message' => '取消收藏失败:' . $e->getMessage()
            ];
        }
    }
    /**
     * 检查是否已收藏
     */
    public function isFavorited($userId, $itemId, $itemType) {
        $sql = "SELECT id FROM user_favorites 
                WHERE user_id = ? AND item_id = ? AND item_type = ?";
        $stmt = $this->db->prepare($sql);
        $stmt->execute([$userId, $itemId, $itemType]);
        return $stmt->rowCount() > 0;
    }
    /**
     * 获取用户收藏列表
     */
    public function getUserFavorites($userId, $itemType = null, $page = 1, $limit = 20) {
        $offset = ($page - 1) * $limit;
        $where = "user_id = ?";
        $params = [$userId];
        if ($itemType) {
            $where .= " AND item_type = ?";
            $params[] = $itemType;
        }
        $sql = "SELECT * FROM user_favorites 
                WHERE {$where} 
                ORDER BY created_at DESC 
                LIMIT ? OFFSET ?";
        $params[] = $limit;
        $params[] = $offset;
        $stmt = $this->db->prepare($sql);
        $stmt->execute($params);
        return $stmt->fetchAll(PDO::FETCH_ASSOC);
    }
}

API路由处理

<?php
// api/favorite.php
header('Content-Type: application/json');
session_start();
require_once 'config/database.php';
require_once 'FavoriteController.php';
// 验证用户登录
if (!isset($_SESSION['user_id'])) {
    echo json_encode(['success' => false, 'message' => '请先登录']);
    exit;
}
$userId = $_SESSION['user_id'];
$action = $_POST['action'] ?? 'toggle';
$itemId = $_POST['item_id'] ?? 0;
$itemType = $_POST['item_type'] ?? 'article';
$db = getDatabaseConnection();
$favoriteController = new FavoriteController($db);
switch ($action) {
    case 'toggle':
        $result = $favoriteController->toggleFavorite($userId, $itemId, $itemType);
        break;
    case 'check':
        $isFavorited = $favoriteController->isFavorited($userId, $itemId, $itemType);
        $result = ['success' => true, 'is_favorited' => $isFavorited];
        break;
    default:
        $result = ['success' => false, 'message' => '无效的操作'];
}
echo json_encode($result);

前端实现

HTML

<button class="favorite-btn" data-id="123" data-type="article">
    <span class="heart-icon">♡</span>
    <span class="favorite-text">收藏</span>
</button>

JavaScript (原生)

// 收藏功能
document.querySelectorAll('.favorite-btn').forEach(btn => {
    btn.addEventListener('click', async function(e) {
        e.preventDefault();
        const itemId = this.dataset.id;
        const itemType = this.dataset.type;
        const userId = document.body.dataset.userId;
        if (!userId) {
            alert('请先登录');
            window.location.href = '/login.php';
            return;
        }
        try {
            const formData = new FormData();
            formData.append('action', 'toggle');
            formData.append('item_id', itemId);
            formData.append('item_type', itemType);
            const response = await fetch('/api/favorite.php', {
                method: 'POST',
                body: formData
            });
            const result = await response.json();
            if (result.success) {
                // 切换收藏按钮状态
                this.classList.toggle('favorited');
                const heartIcon = this.querySelector('.heart-icon');
                const favoriteText = this.querySelector('.favorite-text');
                if (result.action === 'favorited') {
                    heartIcon.textContent = '♥';
                    favoriteText.textContent = '已收藏';
                } else {
                    heartIcon.textContent = '♡';
                    favoriteText.textContent = '收藏';
                }
                // 可选:显示提示信息
                showToast(result.message);
            } else {
                alert(result.message);
            }
        } catch (error) {
            console.error('Error:', error);
            alert('操作失败,请重试');
        }
    });
});
// Toast提示
function showToast(message) {
    const toast = document.createElement('div');
    toast.className = 'toast';
    toast.textContent = message;
    document.body.appendChild(toast);
    setTimeout(() => {
        toast.remove();
    }, 2000);
}

使用 jQuery 的简化版本

// 收藏切换
$('.favorite-btn').click(function() {
    const $btn = $(this);
    const itemId = $btn.data('id');
    const itemType = $btn.data('type');
    // 检查登录状态
    if (!$('body').data('userId')) {
        alert('请先登录');
        return;
    }
    $.ajax({
        url: '/api/favorite.php',
        method: 'POST',
        data: {
            action: 'toggle',
            item_id: itemId,
            item_type: itemType
        },
        success: function(response) {
            if (response.success) {
                $btn.toggleClass('favorited');
                if (response.action === 'favorited') {
                    $btn.find('.heart-icon').text('♥');
                    $btn.find('.favorite-text').text('已收藏');
                } else {
                    $btn.find('.heart-icon').text('♡');
                    $btn.find('.favorite-text').text('收藏');
                }
                // 显示通知
                showNotification(response.message);
            }
        },
        error: function() {
            alert('操作失败,请重试');
        }
    });
});

CSS样式

.favorite-btn {
    display: inline-flex;
    align-items: center;
    padding: 8px 16px;
    border: 1px solid #ddd;
    background: white;
    cursor: pointer;
    transition: all 0.3s ease;
}
.favorite-btn:hover {
    border-color: #e74c3c;
    color: #e74c3c;
}
.favorite-btn.favorited {
    background: #e74c3c;
    color: white;
    border-color: #e74c3c;
}
.heart-icon {
    margin-right: 5px;
    font-size: 18px;
}
.toast {
    position: fixed;
    bottom: 20px;
    left: 50%;
    transform: translateX(-50%);
    background: rgba(0,0,0,0.8);
    color: white;
    padding: 10px 20px;
    border-radius: 4px;
    z-index: 1000;
    animation: fadeInOut 2s ease;
}
@keyframes fadeInOut {
    0% { opacity: 0; }
    10% { opacity: 1; }
    90% { opacity: 1; }
    100% { opacity: 0; }
}

使用示例

<?php
// 文章页面
$isFavorited = $favoriteController->isFavorited($currentUser['id'], $article['id'], 'article');
?>
<button class="favorite-btn <?php echo $isFavorited ? 'favorited' : ''; ?>" 
        data-id="<?php echo $article['id']; ?>" 
        data-type="article">
    <span class="heart-icon"><?php echo $isFavorited ? '♥' : '♡'; ?></span>
    <span class="favorite-text"><?php echo $isFavorited ? '已收藏' : '收藏'; ?></span>
</button>

这个方案实现了:

  • ✅ 收藏/取消收藏切换
  • ✅ 防止重复收藏(数据库唯一索引)
  • ✅ 检查收藏状态
  • ✅ 前端即时反馈
  • ✅ 用户登录验证
  • ✅ 分页获取收藏列表

你可以根据项目需求进行调整和扩展。

抱歉,评论功能暂时关闭!