基于Memos实现哔哔和清单功能

效果预览

  • 哔哔功能预览:点我预览
  • 清单功能预览:点我预览

首先说明,这一切只是我定的规则而已,且功能不多。

哔哔功能

实现

找个页面丢入以下 html + js + css 即可。当然,得先部署个Memos

代码语言:javascript
复制
<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>
pageTalk();
// 页面说说
function pageTalk() {
fetch('https://你的https://你的memos地址/api/memo?creatorId=1&tag=说说&limit=30').then(res => res.json()).then(data => { // 注意修改域名
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.data.forEach(item => { items.push(Format(item)) });
if (items.length == 30) document.querySelector('.limit').style.display = 'block';
items.forEach(item => {
html += &lt;div class=&#34;talk_item&#34;&gt;&lt;div class=&#34;talk_meta&#34;&gt;&lt;img class=&#34;no-lightbox avatar&#34; src=&#34;https://q1.qlogo.cn/g?b=qq&amp;nk=553344777&amp;s=5&#34;&gt;&lt;div class=&#34;info&#34;&gt;&lt;span class=&#34;talk_nick&#34;&gt;Leonus${icon}&lt;/span&gt;&lt;span class=&#34;talk_date&#34;&gt;${item.date}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class=&#34;talk_content&#34;&gt;${item.content}&lt;/div&gt;&lt;div class=&#34;talk_bottom&#34;&gt;&lt;div&gt;&lt;span class=&#34;talk_tag&#34;&gt;# ${item.tag}&lt;/span&gt;&lt;/div&gt;&lt;a href=&#34;javascript:;&#34;onclick=&#34;goComment(&#39;${item.text}&#39;)&#34;&gt;&lt;span class=&#34;icon&#34;&gt;&lt;i class=&#34;fa-solid fa-message fa-fw&#34;&gt;&lt;/i&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt; // 注意修改头像链接和名称
})
document.getElementById('talk').innerHTML = html
})
}
// 页面评论
function goComment(e) {
var n = document.querySelector(".el-textarea__inner")
n.value = &gt; ${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),
imgls = content.match(/(?<=![.*]()(.*?)(?=))/g), // 2023-01-15更新
text = ''
text = content.replace(/#(.*?)\s/g, '').replace(/![(.*?)]((.*?))/g, '').replace(/{(.*?)}/g, '')
content = text.replace(/(?<!!)[(.*?)]((.*?))/g, &lt;a href=&#34;$2&#34;&gt;@$1&lt;/a&gt;);
if (imgls) {
content += &lt;div class=&#34;zone_imgbox&#34;&gt;
imgls.forEach(e => content += &lt;a href=&#34;${e}&#34; data-fancybox=&#34;gallery&#34; class=&#34;fancybox&#34; data-thumb=&#34;${e}&#34;&gt;&lt;img src=&#34;${e}&#34;&gt;&lt;/a&gt;
)
content += '</div>'
}
return {
content: content,
tag: tag ? tag : '无标签',
date: date,
text: text.replace(/(?<!!)[(.*?)]((.*?))/g, '[链接]' + ${imgls?&#39;[图片]&#39;:&#39;&#39;})
}
}
// 页面时间格式化
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>

使用

使用的格式如下:

代码语言:javascript
复制
#说说 {说说标签} 我是内容 我是链接 

注意,前面的#说说 是固定的。标签用大括号包起来。

清单功能

实现

还是找个页面丢入以下 html + js + css 即可。

代码语言:javascript
复制
<style>
/* 页面初始化 */
div#page {
background: none;
border: 0;
padding: 0;
}
[data-theme=dark] #twikoo .tk-content,
#twikoo .tk-content {
padding: 0;
background: transparent;
}

.tk-comments-container>.tk-comment,
.tk-submit:nth-child(1){
background: var(--card-bg);
border: 1px rgba(188, 188, 188, 0.8) solid;
box-shadow: 0 5px 10px rgb(189 189 189 / 10%);
transition: all .3s ease-in-out;
border-radius: 12px;
}

.tk-comments-container>.tk-comment:hover,
.tk-submit:nth-child(1):hover {
border-color: #6dc3fd;
}

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

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

/* 页面初始化结束 */
div#todolist {
display: flex;
flex-wrap: wrap;
margin-top: 1rem;
}
.list_item {
display: inline-block;
width: calc(50% - .4rem);
background: #ffe3dd;
border-radius: 12px;
padding: 10px 1rem 1.2rem;
border: 2px dashed #f7a796;
--todo-border: 1px solid #f7a796;
margin-right: 1rem;
margin-bottom: 1rem;
}
.list_item h3 {
margin: 0;
border-bottom: var(--todo-border);
}
.list_item ul {
font-size: 17px;
padding: 0 !important;
margin: 0;
}
.list_item li{
margin: 0 !important;
border-bottom: var(--todo-border);
}
.list_item li::marker {
content: none;
}
li.achieve {
opacity: .8;
text-decoration: line-through;
}
@media screen and (max-width: 900px) {
div#todolist {
margin: 1rem 5px 0;
}
}
@media screen and (max-width: 768px) {
.list_item{
width: 100%;
}
}
</style>

<div id="todolist"></div>

<script>
// 瀑布流函数,不用管
function waterfall(t){function e(t,e){var n=window.getComputedStyle(e);return parseFloat(n["margin"+t])||0}function n(t){return t+"px"}function r(t){return parseFloat(t.style.left)}function o(t){return t.clientWidth}function l(t){return function(t){return parseFloat(t.style.top)}(t)+function(t){return t.clientHeight}(t)+e("Bottom",t)}function i(t){return r(t)+o(t)+e("Right",t)}function u(t){t=t.sort((function(t,e){return l(t)===l(e)?r(e)-r(t):l(e)-l(t)}))}function a(e){o(t)!=h&&(e.target.removeEventListener(e.type,arguments.callee),waterfall(t))}"string"==typeof t&&(t=document.querySelector(t));var s=[].map.call(t.children,(function(t){return t.style.position="absolute",t}));t.style.position="relative";var f=[];s.length&&(s[0].style.top="0px",s[0].style.left=n(e("Left",s[0])),f.push(s[0]));for(var p=1;p<s.length;p++){var c=s[p-1],y=s[p];if(!(i(c)+o(y)<=o(t)))break;y.style.top=c.style.top,y.style.left=n(i(c)+e("Left",y)),f.push(y)}for(;p<s.length;p++){u(f);y=s[p];var d=f.pop();y.style.top=n(l(d)+e("Top",y)),y.style.left=n(r(d)),f.push(y)}u(f);var v=f[0];t.style.height=n(l(v));var h=o(t);window.addEventListener?window.addEventListener("resize",a):document.body.onresize=a}

// 清单函数
todolist();
function todolist() {
fetch('https://你的https://你的memos地址/api/memo?creatorId=1&tag=清单').then(res => res.json()).then(data => { // 注意替换链接
// 获取并处理数据
data = data.data
let box = document.getElementById('todolist')
data.forEach(item => {
// 处理数据
let content = item.content,
title = content.match(/(?<=#.*[)(.*?)(?=])/g);
// 去掉多余内容,替换清单内容
content = content.replace(/#.*\s/g, '').replace(/(-\s[\s]\s)(.*)(?=\s*)/g, &lt;li&gt;&lt;i style=&#34;margin-right: 5px;&#34; class=&#34;fa-regular fa-circle&#34;&gt;&lt;/i&gt;$2&lt;/li&gt;).replace(/(-\s[x]\s)(.*)(?=\s*)/g, &lt;li class=&#34;achieve&#34;&gt;&lt;i style=&#34;margin-right: 5px;&#34; class=&#34;fa-regular fa-circle-check&#34;&gt;&lt;/i&gt;$2&lt;/li&gt;);
// 渲染数据
let div = document.createElement('div');
div.className = 'list_item';
div.innerHTML = &lt;h3&gt;${title}&lt;/h3&gt;&lt;ul&gt;${content}&lt;/ul&gt;;
box.appendChild(div);
});
waterfall('#todolist');
}).catch()
}
</script>

使用

使用的格式如下:

代码语言:javascript
复制
#清单 [想买的东西]

  • 机械键盘
  • 已完成的清单

注意,前面的#清单 是固定的。标题用中括号包起来。已完成的将括号内的空格改成x即可。