我们将从功能原理、核心代码、数据表结构和实现步骤四个方面来彻底讲明白。

(图片来源网络,侵删)
功能原理概述
DedeCMS 的点赞功能,其核心思想是“计数”和“记录”。
- 计数:每篇文章都有一个独立的点赞总数,当用户点击“赞”时,该文章的点赞数
+1。 - 记录:为了防止用户重复点赞,系统需要记录哪些用户已经给哪些文章点过赞,这通常通过 Cookie 来实现,当用户点赞后,就在他的浏览器里设置一个 Cookie,记录下
文章ID,下次再访问该文章时,程序会先检查这个 Cookie,如果已存在,则不允许再次点赞。
工作流程图:
用户访问文章
|
V和点赞按钮(显示当前点赞数)
|
V
用户点击“赞”按钮
|
V
[前端JS] 发送一个Ajax请求到后端,携带文章ID
|
V
[后端PHP] 接收请求:
1. 检查用户Cookie中是否已存在该文章ID的点赞记录。
2. 如果存在,则返回“已点赞”的提示,不进行任何操作。
3. 如果不存在,则:
a. 更新 `dede_archives` 表中该文章的 `click`(或自定义字段)字段,值 `+1`。
b. 在 `dede_stow`(或自定义表)中插入一条点赞记录。
c. 在用户浏览器中设置一个 Cookie,记录该文章ID。
4. 返回“点赞成功”的提示和最新的点赞数。
|
V
[前端JS] 收到响应后,更新页面上的点赞数,并将按钮变为不可点击状态(或改变样式)。
核心代码解析
一个完整的点赞功能通常涉及三个部分:前端HTML/JS、后端PHP处理程序、以及数据表。
数据表结构
DedeCMS 本身没有专门的点赞表,所以我们通常采用两种方式:

(图片来源网络,侵删)
利用 click 字段(简单计数,不防重复)
dede_archives 表中有一个 click 字段,通常用于记录文章的点击数,我们可以复用它来记录点赞数。
- 优点:无需建新表,非常简单。
- 缺点:无法防止用户重复刷新页面进行“重复点赞”。
新建 dede_likes 表(推荐,功能完整)
为了实现“防重复点赞”,我们需要一个独立的表来记录点赞行为。
CREATE TABLE `dede_likes` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增ID', `aid` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '文章ID', `ip` varchar(20) NOT NULL DEFAULT '' COMMENT '点赞IP地址', `create_time` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '点赞时间戳', PRIMARY KEY (`id`), UNIQUE KEY `aid_ip` (`aid`,`ip`) -- 关键!通过联合唯一索引确保同一IP对同一篇文章只能点赞一次 ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
- 优点:功能完整,可以防止重复点赞,甚至可以扩展出“谁在什么时候点赞”的记录。
- 缺点:需要手动创建数据表。
我们以方式二为例进行讲解,因为它更专业和实用。
前端代码 (HTML + JavaScript)
在文章模板文件 article_article.htm 中,你需要找到合适的位置放置点赞按钮和显示区域。
HTML 部分:
<!-- 在文章内容下方或合适位置添加 -->
<div class="like-box">
<span class="like-count" id="like-count-{dede:field.id/}">0</span> 人觉得很赞
<a href="javascript:;" class="like-btn" id="like-btn-{dede:field.id/}" data-aid="{dede:field.id/}">赞</a>
</div>
id="like-count-{dede:field.id/}":动态的点赞数显示区域,{dede:field.id/}是当前文章的ID。id="like-btn-{dede:field.id/}":动态的点赞按钮。data-aid="{dede:field.id/}":将文章ID作为data-aid属性存储,方便JS获取。
JavaScript 部分 (通常放在底部或引入外部JS文件):
// 等待文档加载完成
$(document).ready(function() {
// 为所有带有 .like-btn 类的元素绑定点击事件
$('.like-btn').on('click', function() {
// 获取按钮对象
var $btn = $(this);
// 获取文章ID
var aid = $btn.data('aid');
// 获取点赞数显示元素
var $count = $('#like-count-' + aid);
// 1. 先检查Cookie,如果已存在,则直接返回
if (getCookie('like_' + aid)) {
alert('您已经点过赞了!');
return;
}
// 2. 发送Ajax请求到后端处理
$.ajax({
type: 'POST',
url: '/plus/like.php', // 后端处理程序的路径
data: {aid: aid},
dataType: 'json',
success: function(response) {
if (response.status == 1) {
// 点赞成功
alert(response.msg);
// 更新页面上的点赞数
$count.text(response.count);
// 禁用按钮,防止重复点击
$btn.text('已赞').addClass('disabled').off('click');
// 设置Cookie,有效期30天
setCookie('like_' + aid, 1, 30);
} else {
// 点赞失败(例如已点过)
alert(response.msg);
}
},
error: function() {
alert('请求失败,请稍后再试!');
}
});
});
});
// 设置Cookie的函数
function setCookie(name, value, days) {
var expires = "";
if (days) {
var date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
expires = "; expires=" + date.toUTCString();
}
document.cookie = name + "=" + (value || "") + expires + "; path=/";
}
// 获取Cookie的函数
function getCookie(name) {
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
}
return null;
}
后端处理代码 (PHP)
在 plus/ 目录下新建一个文件 like.php。
<?php
require_once(dirname(__FILE__) . "/../include/common.inc.php");
// 定义返回给前端的数据格式
$return_data = array('status' => 0, 'msg' => '操作失败', 'count' => 0);
// 1. 获取前端传来的文章ID
$aid = isset($aid) && is_numeric($aid) ? intval($aid) : 0;
if ($aid <= 0) {
$return_data['msg'] = '文章ID无效';
echo json_encode($return_data);
exit;
}
// 2. 检查Cookie,防止重复点赞
$cookie_name = 'like_' . $aid;
if (isset($_COOKIE[$cookie_name])) {
$return_data['status'] = 0;
$return_data['msg'] = '您已经点过赞了!';
// 从数据库获取当前点赞数
$row = $dsql->GetOne("SELECT likes FROM `dede_likes` WHERE `aid` = '{$aid}'");
$return_data['count'] = $row['likes'];
echo json_encode($return_data);
exit;
}
// 3. 执行点赞操作(事务处理确保数据一致性)
$dsql->ExecuteNoneQuery("START TRANSACTION");
// 3.1 在 dede_likes 表中插入记录
$ip = GetIP(); // 获取用户IP地址
$now_time = time();
$rs = $dsql->ExecuteNoneQuery("INSERT INTO `dede_likes` (`aid`, `ip`, `create_time`) VALUES ('{$aid}', '{$ip}', '{$now_time}');");
if ($rs) {
// 3.2 更新 dede_archives 表中的点赞
