基于Zeabur部署Memos实现说说页面

2023-08-20

前言

这几天一直想给博客增加一个说说页面,昨天尝试了用leancloud和artitalk成功部署了页面,但是由于我用的leancloud是国际版的(国内版的需要备案才能使用),所以在国内不用梯子我就加载不出说说页面。于是我就在网上寻找其他的办法,我发现许多人都在用memos,这个比起artitalk访问就快多了,而且也很美观,便想着也部署一个放在我的博客上。由于我在这方面完全是零基础,搭建期间遇到了不少问题,克服了重重困难后,我终于部署成功了。在此写下这篇文章期望能帮到其他和我一样的小白们。

本篇参考了下面两个大佬的教程

子虚栈的一分钟免费部署你的专属 Memos

Leonus的基于Momos实现说说和清单功能

创建Zeabur并部署Memos

这一步可以直接看子虚栈大佬的教程,已经写得很清楚了,一分钟免费部署你的专属 Memos

将Memos部署到博客中

部署页面

首先创建一个新页面,在博客根目录中执行

hexo new page talk(名字可以自定义)

然后记得在主题配置文件中的目录中增加你新创建的talk页面,这样才能在博客菜单中显示“talk”按钮

然后打开blog\source\talk\index.md

在里面增加以下代码(源自Leonus - 进一寸有进一寸的欢喜。))

<style>
/* 页面初始化 */
div#page {
    background: none;
    border: 0;
    padding: 0;
}

[data-theme=dark] #twikoo .tk-content,
#twikoo .tk-content {
    padding: 0;
    background: transparent;
}

.talk_item,
.tk-expand,
.tk-comments-container>.tk-comment,
.tk-submit:nth-child(1){
    background: var(--card-bg);
    border: 1px solid #e0e3ed;
    box-shadow: 0 5px 10px rgb(189 189 189 / 10%);
    transition: all .3s ease-in-out;
    border-radius: 12px;
}
.talk_item:hover,
.tk-comments-container>.tk-comment:hover,
.tk-submit:nth-child(1):hover {
    border-color: #49b1f5;
}

.tk-submit {
    padding: 20px 10px 0;
}

.tk-comments-container>.tk-comment {
    padding: 15px;
}

/* 页面初始化结束 */

#talk{
    margin-top: 1rem;
}

#talk .loading {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
}

#talk .loading img {
    width: 200px;
}

.talk_item {
    display: flex;
    flex-direction: column;
    padding: 20px;
    margin-bottom: 15px;
}

.avatar {
    margin: 0 !important;
    width: 60px;
    height: 60px;
    border-radius: 10px;
}


.talk_bottom,
.talk_meta {
    display: flex;
    align-items: center;
    width: 100%;
    line-height: 1.5;
}
.talk_bottom{
    justify-content: space-between;
}
.info {
    display: flex;
    flex-direction: column;
    margin-left: 10px;
}
span.talk_nick {
    color: #6dbdc3;
    font-size: 1.2rem;
}
svg.is-badge.icon {
    width: 15px;
    margin-left: 5px;
    padding-top: 3px;
}
span.talk_date {
    opacity: .6;
}

.talk_content {
    line-height: 1.5;
    margin-top: 10px;
}
.zone_imgbox {
    display: flex;
    flex-wrap: wrap;
    --w: calc(25% - 8px);
    gap: 10px;
    margin-top: 5px;
}
.zone_imgbox a {
    display: block;
    border-radius: 12px;
    width: var(--w);
    aspect-ratio: 1/1;
    position: relative;
}

.zone_imgbox img {
    width: 100%;
    height: 100%;
    margin: 0 !important;
    object-fit: cover;
}
/* 底部 */

.talk_bottom {
    opacity: .9;
}
.talk_bottom .icon {
    color: var(--font-color);
    float: right;
    transition: all .3s;
}

.talk_bottom .icon:hover {
    color: #49b1f5;
}

span.talk_tag{
    font-size: 14px;
}
.talk_content>a {
    margin: 0 3px;
    color: #ff7d73 !important;
}
.talk_content>a:hover{
    text-decoration: none !important;
    color: #ff5143 !important
}

/* 提醒 */

.limit {
    transition: all .3s ease-in-out;
    color: rgba(76, 73, 72, 0.6);
}

[data-theme=dark] .limit {
    color: rgba(255, 255, 255, 0.5);
}

.limit {
    display: none;
    text-align: center;
    margin-top: 20px;
    color: var(--font-color);
}
@media screen and (max-width: 900px) {
    .zone_imgbox {
        --w: calc(33% - 5px);
    }
    #talk{
        margin: 10px 3px 0
    }
    #post-comment{
        margin: 0 3px
    }
}

@media screen and (max-width: 768px) {
    .zone_imgbox {
        gap: 6px;
    }
    .zone_imgbox {
        --w: calc(50% - 3px);
    }
    span.talk_date {
        font-size: 14px;
    }
}
</style>

<div id="talk">
<div class='loading'><img src="/img/loading.svg" alt="加载中..."></div>
</div>

<div class="limit">- 只展示最近30条说说 -</div>
<script>
if(1) {
    let url = 'https://你的memos地址'//这里地址最后面不要有'/'
    
    fetch(url + '/api/v1/memo?creatorId=你的ID&tag=说说&limit=30').then(res => res.json()).then(data => { // 注意修改"你的ID"
        let items = [],
            html = '',
            icon = '<svg viewBox="0 0 512 512"xmlns="http://www.w3.org/2000/svg"class="is-badge icon"><path d="m512 268c0 17.9-4.3 34.5-12.9 49.7s-20.1 27.1-34.6 35.4c.4 2.7.6 6.9.6 12.6 0 27.1-9.1 50.1-27.1 69.1-18.1 19.1-39.9 28.6-65.4 28.6-11.4 0-22.3-2.1-32.6-6.3-8 16.4-19.5 29.6-34.6 39.7-15 10.2-31.5 15.2-49.4 15.2-18.3 0-34.9-4.9-49.7-14.9-14.9-9.9-26.3-23.2-34.3-40-10.3 4.2-21.1 6.3-32.6 6.3-25.5 0-47.4-9.5-65.7-28.6-18.3-19-27.4-42.1-27.4-69.1 0-3 .4-7.2 1.1-12.6-14.5-8.4-26-20.2-34.6-35.4-8.5-15.2-12.8-31.8-12.8-49.7 0-19 4.8-36.5 14.3-52.3s22.3-27.5 38.3-35.1c-4.2-11.4-6.3-22.9-6.3-34.3 0-27 9.1-50.1 27.4-69.1s40.2-28.6 65.7-28.6c11.4 0 22.3 2.1 32.6 6.3 8-16.4 19.5-29.6 34.6-39.7 15-10.1 31.5-15.2 49.4-15.2s34.4 5.1 49.4 15.1c15 10.1 26.6 23.3 34.6 39.7 10.3-4.2 21.1-6.3 32.6-6.3 25.5 0 47.3 9.5 65.4 28.6s27.1 42.1 27.1 69.1c0 12.6-1.9 24-5.7 34.3 16 7.6 28.8 19.3 38.3 35.1 9.5 15.9 14.3 33.4 14.3 52.4zm-266.9 77.1 105.7-158.3c2.7-4.2 3.5-8.8 2.6-13.7-1-4.9-3.5-8.8-7.7-11.4-4.2-2.7-8.8-3.6-13.7-2.9-5 .8-9 3.2-12 7.4l-93.1 140-42.9-42.8c-3.8-3.8-8.2-5.6-13.1-5.4-5 .2-9.3 2-13.1 5.4-3.4 3.4-5.1 7.7-5.1 12.9 0 5.1 1.7 9.4 5.1 12.9l58.9 58.9 2.9 2.3c3.4 2.3 6.9 3.4 10.3 3.4 6.7-.1 11.8-2.9 15.2-8.7z"fill="#1da1f2"></path></svg>';
        
        data.forEach(item => { items.push(Format(item)) });
        if (items.length == 30) document.querySelector('.limit').style.display = 'block';
        items.forEach(item => {
            html += `<div class="talk_item"><div class="talk_meta"><img class="no-lightbox no-lazyload avatar" src="这里是你头像链接"><span class="talk_nick">名称${icon}</span><span class="talk_date">${item.date}</span></div></div><div class="talk_content">${item.content}</div><div class="talk_bottom"><div><span class="talk_tag"># ${item.tag}</span></div><a href="javascript:;"onclick="goComment('${item.text}')"><span class="icon"><i class="fa-solid fa-message fa-fw"></i></span></a></div></div>` // 注意修改头像链接和名称(直接替换掉)
        })
        document.getElementById('talk').innerHTML = html
    })
    // 页面评论
    function goComment(e) {
        var n = document.querySelector(".el-textarea__inner")
        n.value = `> ${e}\n\n`;
        n.focus();
        btf.snackbarShow("无需删除空行,直接输入评论即可", !1, 2e3);
    }
    // 页面内容格式化
    function Format(item) {
        let date = getTime(new Date(item.createdTs * 1000).toString()),
            content = item.content,
            tag = item.content.match(/\{(.*?)\}/g),
            imgs = content.match(/!\[.*\]\(.*?\)/g), 
            text = ''
        if (imgs) imgs = imgs.map(item => { return item.replace(/!\[.*\]\((.*?)\)/, '$1') })
        if (item.resourceList.length) {
            if (!imgs) imgs = []
            item.resourceList.forEach(t => {
                if (t.externalLink) imgs.push(t.externalLink)
                else imgs.push(`${url}/o/r/${t.id}/${t.publicId}/${t.filename}`)
            })
        }
        text = content.replace(/#(.*?)\s/g, '').replace(/\!\[(.*?)\]\((.*?)\)/g, '').replace(/\{(.*?)\}/g, '')
        content = text.replace(/\[(.*?)\]\((.*?)\)/g, `<a href="$2">@$1</a>`);
        if (imgs) {
            content += `<div class="zone_imgbox">`
            imgs.forEach(e => content += `<a href="${e}" data-fancybox="gallery" class="fancybox" data-thumb="${e}"><img class="no-lazyload" src="${e}"></a>` // 2023-02-06更新
            )
            content += '</div>'
        }
        return {
            content: content,
            tag: tag ? tag[0].replace(/\{(.*?)\}/,'$1') : '无标签',
            date: date,
            text: text.replace(/\[(.*?)\]\((.*?)\)/g, '[链接]' + `${imgs?'[图片]':''}`)
        }
    }
    // 页面时间格式化
    function getTime(time) {
        let d = new Date(time),
            ls = [d.getFullYear(), d.getMonth() + 1, d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds()];
        for (let i = 0; i < ls.length; i++) {
            ls[i] = ls[i] <= 9 ? '0' + ls[i] : ls[i] + ''
        }
        if (new Date().getFullYear() == ls[0]) return ls[1] + '月' + ls[2] + '日 ' + ls[3] +':'+ ls[4]
        else return ls[0] + '年' + ls[1] + '月' + ls[2] + '日 ' + ls[3] +':'+ ls[4]
    }
}
</script>

这里我将代码修改到了适配memos1.4.0以上版本的,如果你的memos版本在1.4.0一下,可以去原教程里找相应的代码,还有要注意的地方就是代码第200行粘贴你的memos地址时记得地址最后不要有‘/’符号

关于Memos用户ID

代码中有一处要修改成你自己的ID,我按照Leonus的教程中关于用户ID获取的方法操作之后,发现本该显示ID的地方显示成了我的用户名1

我原本以为这里的用户名就是我的id,但放到代码中提示是错误的,我在这里卡了好久,在我的一番摸索之下,我发现了一个新的获取id的方法:

点击memos的RSS

2

这里这url中u/后面的数字就是我们的ID

3

将你的ID放到代码中去,就能成功部署说说页面了

使用

在memos中,使用特定的格式,将发布范围设置为所有人可见,发布之后就可以在你的博客页面看到你发的内容了

#说说 {说说标签} 我是内容 [我是链接](链接地址) ![](图片链接)

4

更多

关于更多进阶用法,可以去看基于Momos实现说说和清单功能