2025.11.6 修复评论表情插件
AI摘要 文章介绍了如何修复Typecho博客评论插件Emoticon无法显示表情的问题。问题出在插件的emo.js文件未能正确加载,修复步骤包括确保emo.js在jQuery之后加载,并提供了详细的代码示例。同时,还提供了针对PJAX网站的优化方案,包括避免重复加载、精准触发、事件清理和动态加载。最后,还提供了修改后的footer.php代码,以供参考。
评论没有表情,总感觉少点什么,于是找到了 Emoticon
下载链接:https://github.com/s-Ruthless/Typecho-Plugin-Emoticon
但是将 <?php Emoticon_Plugin::emoOut(); ?> 添加到 comments.php 文件后出现了问题:
文章内点击图标没反应
通过F12查询,发现插件的 emo.js 未能加载
于是尝试修复 JS 加载顺序,若 emo.js 加载在 jQuery 之前,会导致方法定义失败或事件绑定失效,且网络波动会让加载顺序随机变化
解决步骤1
确保 emo.js 在 jQuery 之后加载,在 footer.php 中的引入:
<!-- 美团 CDN 加载 jQuery 3.6.0(比本地快,无需额外下载) -->
<script type="text/javascript" src="https://awp-assets.meituan.net/thh/thh_feb_web_portal/js/jquery-3.6.0.min.js"></script>
<!-- 本地加载 emo.js(已修复事件和插入逻辑) -->
<script type="text/javascript" src="<?php echo $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST']; ?>/usr/plugins/Emoticon/assets/emo.js" defer></script>这里 jQuery 也可以使用其他的,如:
[阿里]https://cdn.staticfile.org/jquery/3.6.0/jquery.min.js
[百度]https://apps.bdimg.com/libs/jquery/3.6.0/jquery.min.js
[奇虎360]https://s.ssl.qhres2.com/baomitu/jquery/3.3.1/jquery.min.js
[BootCDN]https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js
解决步骤2
以上在网站没有开启 PJAX 情况下,正常加载。如果开启了 PJAX ,就会导致打开文章后跳转下一篇或返回首页,加载特别缓慢。
于是提供了以下优化方案
关键优化点说明
- 避免重复加载:用
window.EMO_PLUGIN.loaded标记,emo.js仅加载一次,PJAX切换不重复请求; - 精准触发:只有找到评论输入框(#comment)才执行初始化,首页等无评论区页面不触发,节省资源;
- 事件清理:
PJAX切换时调用destroy()解绑旧事件,避免内存泄漏拖慢页面; - 动态加载:
emo.js用动态创建方式加载,不阻塞页面渲染,且加载完成后才初始化。
替换方案
在 footer.php 中找到这段:
});
}
</script>
<!-- 初始化 -->
<script>
// 初始化main容器修改成:
});
}
</script>
<!-- 表情插件脚本(适配PJAX,优化加载速度) -->
<script>
// 全局标记:避免脚本重复加载
window.EMO_PLUGIN = window.EMO_PLUGIN || {
loaded: false,
init: function() {
// 仅在有评论输入框的页面执行(精准触发)
const commentInput = document.getElementById('comment'); // 替换为你的评论输入框ID
if (!commentInput) return;
// 定义表情核心初始化逻辑(事件委托,支持动态DOM)
function initEmoticon() {
// 表情弹框显示/隐藏
$(document).off('click.emoLogo').on('click.emoLogo', '.OwO-logo', function(e){
e.stopPropagation();
$('.bq-list').toggleClass('active');
// 表情分类切换
$(document).off('click.emoBar').on('click.emoBar', '.OwO-bar-item', function(){
$(this).addClass('active').siblings().removeClass('active');
const idx = $(this).index();
$('.OwO-emoji ul').eq(idx).addClass('active-txt').siblings().removeClass('active-txt');
});
});
// 点击页面其他地方关闭弹框
$(document).off('click.emoDoc').on('click.emoDoc', function(e){
if (!$(e.target).closest('.OwO-logo, .bq-list').length) {
$('.bq-list').removeClass('active');
}
});
// 点击表情插入输入框(原生JS,无依赖)
$(document).off('click.emoItem').on('click.emoItem', '.OwO-item', function(e){
e.stopPropagation();
const txt = $(this).attr('data-title');
if (commentInput) {
if (commentInput.selectionStart || commentInput.selectionStart === 0) {
const startPos = commentInput.selectionStart;
const endPos = commentInput.selectionEnd;
commentInput.value = commentInput.value.substring(0, startPos) + txt + commentInput.value.substring(endPos);
commentInput.focus();
commentInput.selectionStart = commentInput.selectionEnd = startPos + txt.length;
} else {
commentInput.value += txt;
}
}
$('.bq-list').removeClass('active');
});
}
// 首次加载emo.js(仅加载一次)
if (!window.EMO_PLUGIN.loaded) {
window.EMO_PLUGIN.loaded = true;
// 动态加载emo.js,确保在jQuery之后执行
const emoScript = document.createElement('script');
emoScript.src = '<?php echo $_SERVER['REQUEST_SCHEME'] . '://' . $_SERVER['HTTP_HOST']; ?>/usr/plugins/Emoticon/assets/emo.js';
emoScript.defer = true;
emoScript.onload = initEmoticon; // 加载完成后初始化
document.body.appendChild(emoScript);
} else {
// 已加载过,直接重新初始化(适配PJAX切换)
initEmoticon();
}
},
// PJAX切换时清理资源,避免内存泄漏
destroy: function() {
$(document).off('click.emoLogo click.emoBar click.emoDoc click.emoItem');
}
};
// 非PJAX页面:页面加载完成后初始化
if (!<?php echo $this->options->pjaxStatus == 'yes' ? 'true' : 'false'; ?>) {
$(function() {
window.EMO_PLUGIN.init();
});
}
</script>
<!-- 初始化 -->
<script>
// 初始化main容器额外修改:PJAX 回调中添加表情初始化 / 清理(找到 PJAX 配置部分)
原 PJAX 代码片段(接着找到这段):
}).on('pjax:complete', function(event, data, status, xhr, options) {
if (event.relatedTarget) {
if (event.relatedTarget.tagName === 'FORM' && event.relatedTarget.id === 'comment-form') {
// 如果PJAX来源是评论表单,则显示提示信息
let message = (data.responseText.match(/<div class="container">\s*([\s\S]*?)\s*<\/div>/i) || [, ''])[1].trim();
if (message) {
alert(message);
$.pjax({
url: xhr.url.replace(/\/comment$/, '/#comments'),
container: '#main',
fragment: '#main'
});
}
} else if (event.relatedTarget.tagName === 'FORM' && event.relatedTarget.classList.contains('protected')) {
// 如果PJAX来源是加密文章密码表单,则显示提示信息
let message = (data.responseText.match(/<div class="container">\s*([\s\S]*?)\s*<\/div>/i) || [, ''])[1].trim();
if (message) {
alert(message);
}
}
}
// PJAX完成,初始化main容器(包括代码复制功能)
initMain();
}).on('pjax:end', function() {修改成(添加表情初始化 / 清理):
}).on('pjax:complete', function(event, data, status, xhr, options) {
if (event.relatedTarget) {
if (event.relatedTarget.tagName === 'FORM' && event.relatedTarget.id === 'comment-form') {
// 如果PJAX来源是评论表单,则显示提示信息
let message = (data.responseText.match(/<div class="container">\s*([\s\S]*?)\s*<\/div>/i) || [, ''])[1].trim();
if (message) {
alert(message);
$.pjax({
url: xhr.url.replace(/\/comment$/, '/#comments'),
container: '#main',
fragment: '#main'
});
}
} else if (event.relatedTarget.tagName === 'FORM' && event.relatedTarget.classList.contains('protected')) {
// 如果PJAX来源是加密文章密码表单,则显示提示信息
let message = (data.responseText.match(/<div class="container">\s*([\s\S]*?)\s*<\/div>/i) || [, ''])[1].trim();
if (message) {
alert(message);
}
}
}
// PJAX完成:先清理表情事件,再初始化
if (window.EMO_PLUGIN) {
window.EMO_PLUGIN.destroy(); // 清理旧事件,避免内存泄漏
window.EMO_PLUGIN.init(); // 重新初始化表情(适配新页面)
}
// 初始化main容器(包括代码复制功能)
initMain();
}).on('pjax:end', function() {注意事项
- 确保评论输入框的
ID是#comment,如果不是,替换代码中document.getElementById('comment')里的comment为实际ID; - 移除之前在
footer.php中直接插入的表情脚本(避免重复); - 清缓存后测试:
PJAX切换页面时,「网络」面板无重复的emo.js请求,加载速度和无表情插件时一致。
未修改前原版本 footer.php
修改后 footer.php
- 上一篇:测试Live实况图功能
- 下一篇:2025.11.6 修复360全景插件