本文目录导读:

在PHP项目中实现点赞/取消点赞功能,通常需要结合数据库和前端交互,以下是完整的实现方案:
数据库设计
创建一个点赞记录表:
CREATE TABLE likes (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL COMMENT '用户ID',
content_id INT NOT NULL COMMENT '内容ID',
content_type VARCHAR(50) NOT NULL COMMENT '内容类型,如article, comment等',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY unique_like (user_id, content_id, content_type)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
表(如articles)中添加点赞数字段:
ALTER TABLE articles ADD COLUMN likes_count INT DEFAULT 0;
PHP后端实现
点赞/取消点赞接口
<?php
// like.php
session_start();
require_once 'db.php'; // 数据库连接文件
header('Content-Type: application/json');
if (!isset($_SESSION['user_id'])) {
echo json_encode(['success' => false, 'message' => '请先登录']);
exit;
}
$user_id = $_SESSION['user_id'];
$content_id = intval($_POST['content_id']);
$content_type = $_POST['content_type'] ?? 'article';
// 检查是否已点赞
$stmt = $pdo->prepare("SELECT id FROM likes WHERE user_id = ? AND content_id = ? AND content_type = ?");
$stmt->execute([$user_id, $content_id, $content_type]);
$like = $stmt->fetch();
if ($like) {
// 已点赞,取消点赞
$pdo->beginTransaction();
try {
// 删除点赞记录
$stmt = $pdo->prepare("DELETE FROM likes WHERE id = ?");
$stmt->execute([$like['id']]);
// 更新内容点赞数
$table = $content_type == 'article' ? 'articles' : 'comments';
$stmt = $pdo->prepare("UPDATE $table SET likes_count = likes_count - 1 WHERE id = ?");
$stmt->execute([$content_id]);
$pdo->commit();
echo json_encode([
'success' => true,
'liked' => false,
'likes_count' => getLikesCount($pdo, $content_id, $content_type)
]);
} catch (Exception $e) {
$pdo->rollBack();
echo json_encode(['success' => false, 'message' => '操作失败']);
}
} else {
// 未点赞,执行点赞
$pdo->beginTransaction();
try {
// 添加点赞记录
$stmt = $pdo->prepare("INSERT INTO likes (user_id, content_id, content_type) VALUES (?, ?, ?)");
$stmt->execute([$user_id, $content_id, $content_type]);
// 更新内容点赞数
$table = $content_type == 'article' ? 'articles' : 'comments';
$stmt = $pdo->prepare("UPDATE $table SET likes_count = likes_count + 1 WHERE id = ?");
$stmt->execute([$content_id]);
$pdo->commit();
echo json_encode([
'success' => true,
'liked' => true,
'likes_count' => getLikesCount($pdo, $content_id, $content_type)
]);
} catch (Exception $e) {
$pdo->rollBack();
echo json_encode(['success' => false, 'message' => '操作失败']);
}
}
function getLikesCount($pdo, $content_id, $content_type) {
$table = $content_type == 'article' ? 'articles' : 'comments';
$stmt = $pdo->prepare("SELECT likes_count FROM $table WHERE id = ?");
$stmt->execute([$content_id]);
return $stmt->fetchColumn();
}
?>
前端实现
HTML结构
<div class="like-container">
<button class="like-btn" data-content-id="123" data-content-type="article">
<i class="heart-icon">❤</i>
<span class="likes-count">0</span>
</button>
</div>
JavaScript交互
// 使用原生JavaScript
document.querySelectorAll('.like-btn').forEach(btn => {
btn.addEventListener('click', function() {
const contentId = this.dataset.contentId;
const contentType = this.dataset.contentType;
// 发送AJAX请求
fetch('like.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `content_id=${contentId}&content_type=${contentType}`
})
.then(response => response.json())
.then(data => {
if (data.success) {
// 更新UI
const heartIcon = this.querySelector('.heart-icon');
const countSpan = this.querySelector('.likes-count');
// 切换点赞状态
if (data.liked) {
this.classList.add('liked');
heartIcon.textContent = '❤️';
} else {
this.classList.remove('liked');
heartIcon.textContent = '♡';
}
// 更新点赞数
countSpan.textContent = data.likes_count;
} else {
alert(data.message);
}
})
.catch(error => console.error('Error:', error));
});
});
// 如果使用jQuery
$('.like-btn').on('click', function() {
const contentId = $(this).data('content-id');
const contentType = $(this).data('content-type');
$.ajax({
url: 'like.php',
method: 'POST',
data: {
content_id: contentId,
content_type: contentType
},
success: function(data) {
if (data.success) {
const $btn = $(this);
$btn.toggleClass('liked');
$btn.find('.likes-count').text(data.likes_count);
if (data.liked) {
$btn.find('.heart-icon').text('❤️');
} else {
$btn.find('.heart-icon').text('♡');
}
} else {
alert(data.message);
}
},
error: function() {
alert('请求失败,请重试');
}
});
});
前端CSS样式
.like-btn {
background: none;
border: 1px solid #ddd;
border-radius: 20px;
padding: 5px 15px;
cursor: pointer;
transition: all 0.3s;
display: inline-flex;
align-items: center;
gap: 5px;
}
.like-btn:hover {
background: #f0f0f0;
}
.like-btn.liked {
color: #e74c3c;
border-color: #e74c3c;
background: #fde8e8;
}
.heart-icon {
font-size: 18px;
}
.likes-count {
font-size: 14px;
font-weight: bold;
}
优化建议
缓存优化
// 使用Redis缓存点赞数
function getLikeCountCache($content_id, $content_type) {
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$key = "likes:{$content_type}:{$content_id}";
$count = $redis->get($key);
if ($count === false) {
// 从数据库获取并缓存
$dbCount = getLikesCountFromDB($content_id, $content_type);
$redis->set($key, $dbCount, 3600); // 缓存1小时
return $dbCount;
}
return $count;
}
防重复点击
let isLoading = false;
$('.like-btn').on('click', function() {
if (isLoading) return;
isLoading = true;
// ... 请求代码 ...
// 请求完成后
isLoading = false;
});
完整示例代码
完整的实现还包括:
- 用户登录状态检查
- 点赞记录查询(页面加载时显示用户是否已点赞)
- 点赞动画效果
- 错误处理
如果需要完整的项目结构代码,我可以提供更详细的实现。