单页Memos添加Artalk评论,无限接近微博
书接上文《使用memos搭建独立微博,self-host三件套齐全了》
本文介绍:
1、Memos应用中添加Artalk评论
2、Typecho集成单页Memos并添加Artalk评论
Memos应用中添加Artalk评论
首先,你需要自建Artalk评论服务,可参考官网,此处不详细介绍了。
然后,在Memos的设置-系统
中添加自定义样式和自定义脚本。
1、在自定义脚本中追加如下代码
将代码中Artalk相关的参数配置,替换为自己的。
// artalk comments
// css
document.head.innerHTML += '<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/artalk/2.5.4/Artalk.css" type="text/css"/>';
// js
function addArtalkJS() {
var memosArtalk = document.createElement("script");
memosArtalk.src = `https://cdn.bootcdn.net/ajax/libs/artalk/2.5.4/Artalk.js`;
var artakPos = document.getElementsByTagName("script")[0];
artakPos.parentNode.insertBefore(memosArtalk, artakPos);
};
// div
function startArtalk() {
start = setInterval(function(){
var artalkDom = document.getElementById('Comments') || '';
var memoAt = document.querySelector('.memo-wrapper') || ''; // 0.12.x的版本请将.memo-wrapper替换为.memo-container
var memoLoading = document.querySelector('.action-button-container') || '';
var memoLoadingA = document.querySelector('.action-button-container a') || '';
if(window.location.href.replace(/^.*\/(m)\/.*$/,'$1') == "m" && memoLoadingA){
memoLoading.innerHTML = "评论加载中……"
}
if(window.location.href.replace(/^.*\/(m)\/.*$/,'$1') == "m" && !artalkDom){
addArtalkJS()
if(memoAt){
clearInterval(start)
memoAt.insertAdjacentHTML('afterend', '<div id="Comments"></div>');
setTimeout(function() {
Artalk.init({
el: '#Comments',
pageKey: location.pathname,
pageTitle: document.title,
server: 'https://artalk.skyue.com',
site: '拾月微博',
darkMode: 'auto'
});
Artalk.on('list-loaded', function() {
// console.log('评论加载完成');
memoLoading.innerHTML = ''
startArtalk();
});
}, 1000);
}
}
//console.log(window.location.href);
}, 1000)
}
startArtalk();
2、在自定义样式中追加如下代码
a.time-text:after { content: ' 评论 💬 '; }
.atk-main-editor { margin-top: 20px; }
最终效果如下:
Typecho集成单页Memos并添加评论
先来欣赏下集成后效果,如下图所示。主要特点在于:评论框默认折叠,点击评论后评论框在当前页展开,无需跳转,类似微博。(点击这里线上体验)
网上有很多Memos单页应用示例代码,比如我用过一段时间木老师开发的版本。
我的博客是Typecho搭建的,有服务端,这次我直接在主题(我用的默认主题)文件夹新建了一个memos.php
的模板文件,并在服务端直接获取Memos数据并渲染,代码如下:
<?php $this->need('header.php'); ?>
<?php if (!defined('__TYPECHO_ROOT_DIR__')) exit;
/**
* Memos模板
*
* @package custom
*/
?>
<div class="col-mb-12 col-8" id="main" role="main">
<article class="post"><h2 class="post-title"></h2><article>
<?php
$url = 'https://memos.skyue.com/api/memo?creatorId=1&limit=300'; // 不限定内容类型
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 跳过证书检查
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); // 从证书中检查 SSL 加密算法是否存在
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 6);
$response = curl_exec($ch);
if($error=curl_error($ch)){
echo '微博加载错误';
}
curl_close($ch);
$array_data = json_decode($response,true)['data'];
for($i=1; $i<count($array_data); $i++)
{
$obj = $array_data[$i];
// 下面这个if判断,是只展示最近30天的Memos
if(time() - $obj['createdTs'] < 2592000){
$memo_id = $obj['id'];
$content = $obj['content'];
$create_time = date('Y-m-d H:i:s',$obj['createdTs']);
$resources = $obj['resourceList'];
$content_tag = preg_replace_callback('/#([^\s\n]+)(?=\s|\n|$)/', function ($matches) {
return '<span class="memo_tag">#' . $matches[1] . '</span>';
}, $content);
$content_html = Typecho_Widget::widget('Widget_Abstract_Contents')->markdown($content_tag); // 使用Typecho自带的Markdown解析器解析Memos
$body_html = sprintf('
<div class="memo-top-wrapper">拾月 · %s</div>
<div class="memo-content-wrapper">%s</div>', $create_time, $content_html);
if($resources){
$image_html = '<div class="resource-wrapper"><div class="images-wrapper"><div class="w-full memo-resource">';
for($j=0; $j<count($resources); $j++){
$image_html = $image_html.sprintf('<img src="%s" decoding="async" loading="lazy">', $resources[$j]['externalLink']);
}
echo '<article class="memo-wrapper">'.$body_html.$image_html.'</div></div></div><a style="cursor:pointer" onclick="loadArtalk(\''.$memo_id.'\')"><span id="btn_memo_'.$memo_id.'">评论</span>(<span id="ArtalkCount" data-page-key="/m/'.$memo_id.'"></span>)</a><div style="display: none;" id="memo_'.$memo_id.'"></div></article>';
}else{
echo '<article class="memo-wrapper">'.$body_html.'<a style="cursor:pointer" onclick="loadArtalk(\''.$memo_id.'\')"><span id="btn_memo_'.$memo_id.'">评论</span>(<span id="ArtalkCount" data-page-key="/m/'.$memo_id.'"></span>)</a><div style="display: none;" id="memo_'.$memo_id.'"></div></article>';
} // echo的html代码中,onclick属性调用下面的加载Artalk评论框代码,需要传memo_id参数
}
}
?> <!-- Memos数据处理结束 -->
<div class="memo-bottom">更多内容前往<a href="https://memos.skyue.com" target="_blank">微博主站</a></div>
</div>
<!-- artalk文件 -->
<link href="https://npm.elemecdn.com/artalk@2.5.4/dist/Artalk.css" rel="stylesheet">
<script src="https://npm.elemecdn.com/artalk@2.5.4/dist/Artalk.js"></script>
<!-- 下面这段JS,在页面上点击评论按钮时触发,支持展开评论和收起评论 -->
<script>
function loadArtalk(memo_id){
const commentDiv = document.getElementById('memo_'+memo_id);
const commentBtn = document.getElementById('btn_memo_'+memo_id);
if(commentDiv.style.display==='none'){
commentDiv.style.display='block';
commentBtn.innerHTML = '收起评论';
new Artalk({
el: '#memo_' + memo_id, // 绑定元素的 Selector
pageKey: '/m/'+memo_id, // 固定链接 (留空自动获取)
pageTitle: '拾月微博', // 页面标题 (留空自动获取)
server: 'https://artalk.skyue.com', // 后端地址
site: '拾月微博', // 在后端中创建的站点名
});
}
else{
commentDiv.style.display='none';
commentBtn.innerHTML = '评论';
}
}
</script>
<!-- 这段js,在未展开评论时,就展示评论数量 -->
<script>
Artalk.loadCountWidget({
server: 'https://artalk.skyue.com',
site: '拾月微博',
pvEl: '#ArtalkPV',
countEl: '#ArtalkCount',
});
</script>
<?php $this->need('footer.php'); ?>
上面这段代码实现两个功能:
- 通过api抓取Memos数据并直接在服务端渲染。
- 提供了两段javascript代码,一个实现展示评论数,一个实现评论框的展开和收起。
如果是Typecho博客程序,大概率能使用上述代码,只根据自己的情况修改Memos api地址以及loadArtalk中server
和site
两个参数。
关于点击「评论」按钮的功能,关键是下面三处:
- 模板中每条memo下面预留一个
div
容器,容器id
为memo_{memo_id}
,渲染后类似<div id="memo_1"></div>
。其作用是在对应的memo下方加载评论框。 - 为「评论」按钮添加
onclick
属性,调用loadArtalk
函数,调用时带上memo_id
参数。这段js执行时,会寻找上面提到的容器,加载评论框,并获取对应Memo的评论进行展示。展开状态再点击,又会收起。 - 「评论」按钮括号内的评论数,是
<span id="ArtalkCount" data-page-key="/m/'.$memo_id.'"></span>
起的作用。
下面是在主题文件夹style.css中追加的样式:
/* memo专用css */
article.memo-wrapper {
padding: 15px;
border: 1px solid darkgray;
margin: 20px 0px;
}
.memo-content-wrapper {
line-height: 1.6;
font-size: 17px;
word-wrap: break-word;
}
.memo-resource img {
width: auto;
max-width: 100%;
}
span.memo_tag {
color: cornflowerblue;
}
.memo-bottom {
margin: 50px 0px;
text-align: center;
}
.memo-top-wrapper {
color: gray;
}
以上,就这么点东西,周六晚上肝到凌晨4点,还好有ChatGPT。
另外,有些不完美的地方,比如:
- 现在图片是纵向平铺的,没有做九宫格缩略图。
- 没有详情页,从评论通知邮件打开Memos,还是memos.skyue.com站点。
留坑,有空再解决这两个问题,尤其是第2个,非常想在www.skyue.com主站实现memos详情页,技术上肯定可行,只是现在还不会。
大家都开始添加评论功能,这手痒痒呀~
哈哈,搞起来。没有评论都不完整😂
不错不错!👍 教程拿走了。
看你的memos评论报错了,感觉是没有添加「可信域名」
嗯嗯,是的😂
看看https://github.com/kingwrcy/mblog-backend这个,多用户+评论的memos版!
上周也看到这个项目,且观察一段时间。
我对多用户没诉求,不过是想要评论,但mblog的评论需要登录,我还是喜欢Typecho这种填个邮箱就能评论的,不用注册登录。
看来我也要学习一下,怎么整起来?不知有没具体教程,业务人士😂
docker安装的话还是挺方便的。
https://www.skyue.com/23021116.html
我在上面这篇文章中简单介绍了docker安装memos的步骤。
这个不错,谢谢分享,参考一些代码,把我的 memos 也加上了评论。
在你的memos上尝试评论,返回如下错误:
{"success":false,"msg":"无效的请求, 无法获取
origin
","data":{}}遇到安全域名跨域问题。谢谢提醒!
Memos 应用上的评论代码有作业可以抄吗?
js如下:
css如下:
js有一些瑕疵,会导致memos设置中的系统设置界面排版出错,没去深究,但整体不影响使用。
把这部分:
修改为:
可以避免在后台加载 CSS 文件,只在 URL 中有
/m/
路径时才加载。后台就不会乱了。赞,把我的也修改了,现在舒服多了,哈哈。
另:url已修改。
Memos 0.13.0 版本好像不能用,改天再研究研究。
TG 的 Memos 广场置顶消息:
Memos 升级到最新的 1.3.0 版本,原来的 Twikoo 评论不能正常显示了。要把原来代码中的.memo-container 改为.memo-wrapper。
应该是 html 元素的 class 属性值变了,试试。
谢谢!
看起来清爽多了,这个字体也挺好👍
霞鹜文楷,啥时候操作系统默认支持就好了,现在都是靠js和css,始终不太友好。
现在玩memos的人真多,我也跟疯了。。
确实好用,还有热心开发者做了ios和android app,非常方便。
总的来讲,社区很活跃。
挺好的方案,听说官方也在做了
是的,也很期待官方评论功能。但看github上的信息,感觉是登录用户的评论,不知是否支持非登录用户。这个还挺重要的。
Memos 今天发布的 0.16.0 版已经支持评论功能啦,不过确实是只有登录用户才能评论。官方的评论其实就是一条和被评论 Memo 链接起来的 Memo,感觉要支持游客评论的话其实也就是支持游客发表 Memo 了。
评论和Memos在数据库中可以存为两表,数据分开。
现在的逻辑是,共用一个表,把评论当Memos。
这个功能的设计,确实有些复杂,感觉怎么弄都有不合适的地方。不能苛求官方。
这个不错,还想着有空实现一下这个功能,正好可以参考一下。
另外,在想有没有可能将一条笔记绑定一个空的评论,然后把这条评论的点赞(同意)按钮放到评论按钮旁边,这样可以利用Artalk简单实现点赞功能。😎
点赞功能这样操作过于track,直接给artalk提个FR比较合适,也确实挺好奇的,都加了pv功能,为啥不加个点赞交互,感觉差不多。
有评论的感觉就很棒,鲜枣折腾博客搞出问题先问GPT已经成习惯了,好用
我还没完全形成习惯,但折腾不动的时候会突然想到,为什么不问问ChatGPT。
确实好用,大杀器。
这个想法很有趣 抄了抄了😂
Typecho博客应该能直接食用