Typecho博客自定义评论区结构
0 前言
我在Typecho默认主题的基础上做了一款自己的主题,但Typecho自带的评论区结构不利于CSS样式设计,因此自己重构了结构,在此记录下。主要参考了typecho官方教程《自定义评论列表区域》。
1 评论区结构设计与实现
- 首先是设计好单条评论的HTML代码结构,如
<li id="comment-7" class="comment-body comment-parent comment-odd">
<div class="comment-header">
<img class="avatar" loading="lazy" src="avatar.png">
<div class="comment-info">
<div>
<span class="username"><a href=评论者主页 rel="external nofollow">评论者名字</a></span>
</div>
<div class="comment-meta">
<span class="comment-time">评论时间</span>
<span class="comment-source">系统名称</span>
<span class="comment-source">浏览器</span>
</div>
</div>
</div>
<div class="comment-content">评论内容</div>
<div class="comment-children">
<!-- 嵌套评论相关 -->
</div>
</li>
- 然后根据设计好的结构,重构
threadedComments函数,函数中<li></li>标签内部的内容为使用typecho系统中的评论变量替换HTML中相关属性后的结果,如下
<?php function threadedComments($comments, $options) {
$commentClass = '';
if ($comments->authorId) {
$commentClass = ($comments->authorId == $comments->ownerId) ? ' comment-by-author' : ' comment-by-user';
}
$info = parseClientInfo($comments->agent);
global $parent_author;
if ($comments->parent == 0) {
$parent_author = '';
}
?>
<li id="<?php $comments->theId(); ?>" class="comment-body<?php
if ($comments->levels > 0) {
echo ' comment-child';
$comments->levelsAlt(' comment-level-odd', ' comment-level-even');
} else {
echo ' comment-parent';
}
$comments->alt(' comment-odd', ' comment-even');
echo $commentClass;
?>">
<div class="comment-header">
<img class="avatar" loading="lazy" src="<?php echo customGravatar($comments->mail, 100); ?>">
<div class="comment-info">
<div>
<span class="username"><?php $comments->author(); ?></span>
<?php if ($comments->authorId == $comments->ownerId): ?><span class="is-author">作者</span><?php endif; ?>
</div>
<div class="comment-meta">
<span class="comment-time"><?php $comments->date(); ?></span>
<span class="comment-source">
<i class="<?php echo $info['system']['icon']; ?>"></i> <?php echo $info['system']['name']; ?>
</span>
<span class="comment-source">
<i class="<?php echo $info['browser']['icon']; ?>"></i> <?php echo $info['browser']['name']; ?>
</span>
</div>
</div>
</div>
<div class="comment-content">
<?php if($parent_author): ?>
<span class="username"><?php echo $parent_author; ?></span>
<?php endif; ?>
<?php $comments->content(); ?>
</div>
<div class="comment-reply"><i class="fas fa-reply"></i> <?php $comments->reply(); ?></div>
<?php if ($comments->children): ?>
<?php $parent_author = '@' . htmlspecialchars($comments->author); ?>
<div class="comment-children"><?php $comments->threadedComments($options); ?></div>
<?php endif; ?>
</li>
<?php } ?>
- 因为是重写了typecho的内部函数,所以可以直接使用原有的调用方式,即
<?php $comments->listComments(); ?>
2 关键功能
2.1 子评论中添加@父评论作者
采用全局变量$parent_author传递父评论作者信息。若当前评论层级为顶级,则设为空,即不存在更高一级的评论;当存在子评论时,将该参数赋值为'@' . htmlspecialchars($comments->author),即@当前评论作者,这样嵌套循环至子评论时,就是@父评论作者。关键代码为以下几行
global $parent_author;
if ($comments->parent == 0) {
$parent_author = '';
}
......
<?php if($parent_author): ?>
<span class="username"><?php echo $parent_author; ?></span>
<?php endif; ?>
......
<?php if ($comments->children): ?>
<?php $parent_author = '@' . htmlspecialchars($comments->author); ?>
<div class="comment-children"><?php $comments->threadedComments($options); ?></div>
<?php endif; ?>
2.2 文章作者评论时添加作者标识
利用评论作者IDauthorId与文章所有者IDownerId是否相同来判断,关键代码如下
<?php if ($comments->authorId == $comments->ownerId): ?><span class="is-author">作者</span><?php endif; ?>
2.3 更多的评论者信息
显示评论者的操作系统、浏览器名称,评论数据库中的agent字段记录了评论者的user-agent,通过解析其中的字段获取相关信息,此功能需要自行编写一个解析函数parseClientInfo($comments->agent),关键代码如下
$info = parseClientInfo($comments->agent);
......
<span class="comment-source">
<i class="<?php echo $info['system']['icon']; ?>"></i> <?php echo $info['system']['name']; ?>
</span>
<span class="comment-source">
<i class="<?php echo $info['browser']['icon']; ?>"></i> <?php echo $info['browser']['name']; ?>
</span>
解析函数parseClientInfo($comments->agent)可以使用AI直接生成,我用腾讯元宝生成函数源码如下。其中我额外采用了font-awesome 6.7.2版本用来显示各种操作系统图标。
<?php
/**
* 获取客户端系统、浏览器信息
*/
function parseClientInfo($userAgent) {
$userAgent = (string) $userAgent;
$systemDefault = ['name' => 'Unknown', 'icon' => 'fas fa-question-circle'];
$browserDefault = ['name' => 'Unknown', 'icon' => 'fas fa-globe'];
$systems = [
'/Windows NT 10\\.0/i' => ['Windows 10', 'fab fa-windows'],
'/Windows NT 6\\.3/i' => ['Windows 8.1', 'fab fa-windows'],
'/Windows NT 6\\.2/i' => ['Windows 8', 'fab fa-windows'],
'/Windows NT 6\\.1/i' => ['Windows 7', 'fab fa-windows'],
'/Windows NT 6\\.0/i' => ['Windows Vista', 'fab fa-windows'],
'/Windows NT 5\\.1/i' => ['Windows XP', 'fab fa-windows'],
'/Ubuntu/i' => ['Ubuntu', 'fab fa-ubuntu'],
'/Macintosh; Intel Mac OS X/i' => ['Mac OS', 'fab fa-apple'],
'/iPad/i' => ['iPad', 'fas fa-apple'],
'/Android/i' => ['Android', 'fas fa-mobile-alt'],
'/iPhone OS/i' => ['IOS', 'fas fa-mobile-alt'],
'/Linux/i' => ['Linux', 'fab fa-linux'],
'/CrOS/i' => ['Unknown', 'fas fa-question-circle']
];
$browsers = [
'/Edg/i' => ['Edge', 'fab fa-edge'],
'/OPR/i' => ['Opera', 'fab fa-opera'],
'/SamsungBrowser/i' => ['Unknown', 'fas fa-globe'],
'/QQBrowser/i' => ['Unknown', 'fas fa-globe'],
'/WeChat/i' => ['Unknown', 'fas fa-globe'],
'/Chrome/i' => ['Chrome', 'fab fa-chrome'],
'/Firefox/i' => ['Firefox', 'fab fa-firefox'],
'/Safari/i' => ['Safari', 'fab fa-safari'],
'/Trident/i' => ['IE', 'fab fa-internet-explorer']
];
$systemResult = $systemDefault;
foreach ($systems as $pattern => $info) {
if (preg_match($pattern, $userAgent)) {
$systemResult = ['name' => $info[0], 'icon' => $info[1]];
break;
}
}
$browserResult = $browserDefault;
foreach ($browsers as $pattern => $info) {
if (preg_match($pattern, $userAgent)) {
$browserResult = ['name' => $info[0], 'icon' => $info[1]];
break;
}
}
return ['system' => $systemResult, 'browser' => $browserResult];
<?php } ?>
2.4 自定义评论时间样式
默认的评论时间样式很丑,我更习惯年-月-日 时:分的显示样式,设置方法为进入typecho网站后台->设置->评论,设置评论日期格式为
Y/m/d H:i
其它样式参考PHP 日期格式写法。
3 评论区数据库字段
typecho官方博客《Typecho数据库设计》详细介绍了评论区的数据库结构,倘若想添加其它功能,如显示评论者IP属地,可通过解析数据库中的ip字段获取。我暂时没有做这一步,有点麻烦。
4 后记
在AI如此成熟的时代,网站设计技术已经变得十分容易,就像我可以完全不懂PHP语言,但使用AI几分钟就可以实现一个user-agent的解析函数。当然,这需要能够给AI明确的表达出自己的想法,需求越具体、描述的越清楚,AI实现的效果就会越好。在我看来,未来可能更侧重于"我想做什么"、"我想使用什么实现什么"等,在相对较为成熟的领域内,有需求和想法可能要大于能够实现的能力本身。