本文目录导读:

在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>
这个方案实现了:
- ✅ 收藏/取消收藏切换
- ✅ 防止重复收藏(数据库唯一索引)
- ✅ 检查收藏状态
- ✅ 前端即时反馈
- ✅ 用户登录验证
- ✅ 分页获取收藏列表
你可以根据项目需求进行调整和扩展。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播