PHP后端只负责接收POST请求、校验用户、写数据库并返回JSON,点赞动画等交互由前端JS控制;接口需防重复提交和CSRF,统一返回{"status":"success","count":127,"liked":true}格式。

PHP后端只负责存数据,别碰JS动画逻辑
点赞的交互动画(比如爱心变色、数字跳动、小红点弹出)必须由前端JS控制,PHP唯一该干的事是接收POST请求、校验用户、写数据库、返回JSON结果。混着写容易导致点击无响应、重复提交、状态不同步。
- PHP接口返回格式统一用
{"status":"success","count":127,"liked":true},不要渲染HTML片段 - 后端不输出任何
<script>标签或内联JS——这会让缓存失效、XSS风险上升、调试困难 - 用户身份靠
$_SESSION['user_id']或JWT token验证,别依赖Cookie名或IP
JS用fetch发请求,禁用jQuery.ajax
现代浏览器原生fetch足够可靠,且配合async/await写法清晰,避免jQuery时代常见的回调地狱和done/fail误用。
- 按钮点击后立刻禁用
btn.disabled = true,防止连点;成功后再恢复 - 用
btn.classList.toggle('liked')切换CSS状态,而不是手动改innerHTML - 失败时显示toast提示,但不要清空已更新的UI——比如点完发现网络断了,本地计数器先+1,等重试再同步
async function toggleLike(postId) {
const btn = document.querySelector(`[data-post="${postId}"]`);
const countEl = btn.querySelector('.like-count');
const isLiked = btn.classList.contains('liked');
try {
const res = await fetch('/api/like.php', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({post_id: postId, action: isLiked ? 'cancel' : 'like'})
});
const data = await res.json();
if (data.status === 'success') {
btn.classList.toggle('liked');
countEl.textContent = data.count;
}
} catch (e) {
// 网络错误时保留本地状态,提示用户“稍后重试”
}
}
PHP接口要防重复提交和CSRF
没加防护的点赞接口,很容易被脚本刷量或跨站伪造请求。关键不是“能不能点”,而是“这次点击是否合法且唯一”。
使用 JSON Schema 验证 JSON 数据,从示例 JSON 生成 schema,并将其转换为 TypeScript 接口、Python 数据类或 Markdown 文档。
- 每个点赞请求必须带一次性
token(存在$_SESSION['like_token']里),PHP收到后立即unset($_SESSION['like_token']) - 数据库用
INSERT ... ON DUPLICATE KEY UPDATE或REPLACE INTO保证同一用户对同一内容只记一条记录 - 检查
HTTP_REFERER只作辅助,不能当主要验证手段;重点看$_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest'是否为AJAX请求
动画卡顿?检查CSS transition和will-change
点赞按钮缩放、颜色渐变看起来卡,大概率是浏览器没开启硬件加速或重绘范围过大,跟PHP完全无关。
立即学习“PHP免费学习笔记(深入)”;
- 给点赞按钮加
transform: scale(1); will-change: transform;,触发GPU加速 - 避免在
:hover里同时改background-color和box-shadow——选一个做动画,另一个静态 - 数字变化用
counter-increment或requestAnimationFrame逐帧更新,别直接textContent = newCount硬切
最常被忽略的是:PHP返回的count值可能比前端本地计数慢半拍,尤其在高并发场景下。如果用户快速连点两次,后端可能只处理一次,但前端动画已经播了两遍——这时得靠服务端返回的liked字段强制重置UI状态,而不是相信“点了就一定变了”。


















