此内容根据文章生成,并经过人工审核,仅用于文章内容的解释与总结
Solitude主题的即刻短文至目前为止仅仅只有静态yml部署方式。当你需要发一条说说时,就得打开电脑,手动去添加yml的内容,再部署上线。本地化的增删,繁琐“即刻短文”。
而MeuiCat在很早之前就已经实现了动态Json以及动态Memos数据的部署方式。你只需要像发朋友圈那样,输入后点击发送即可。
功能实现 让我们一步步解析实操,体验享受代码的乐趣。
动态Json 通俗易懂的解释一下大致的处理过程。通过Fetch获取Json的数据,将遍历数据,根据结构生成各个部分功能,如图片、音乐、视频等,拼接在一起,根据数量限制去循环列表。将生成的HTML插入页面。
其中,加入了一些样式的切换,毕竟Solitude有两套即刻的样式。再就是即刻短文显示的条数逻辑了,这里的规则为:-1等于显示全部内容;当为正数即为限制显示数量,并且当你发布的即刻数量低于你所限制的数量时,Tips
将会贴心的为你提示:已展开所有短文。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 script. (()=>{ const replaceSymbol = (str) => { return str.replace(/[\p{P}\p{S}]/gu, "-") } let says = "" fetch("!{url_for(theme.says.mode_link)}") .then(response => response.json()) .then(str => { for(let i = 0; i < str.length; i++){ let list = "" let listResult = "" let saysList = str[i].essay_list let style = !{theme.says.style} let strip = !{theme.says.strip} let saysTips = "" if (strip === -1 || strip >= str[i].essay_list.length) { list = saysList saysTips = `<div id="bber-tips">- 已展开所有短文 -</div>` } else { list = saysList.slice(0, strip) saysTips = `<div id="bber-tips">- 只展示最近 ${strip} 条短文 -</div>` } for(let j = 0; j < list.length; j++){ let content = "" let onclick = "" if (list[j].content === undefined || list[j].content === null) { content = "" } else if (list[j].content) { content = `<p class="datacont">${list[j].content}</p>` onclick = `<a class="bber-reply goComment" onclick="sco.toTalk('${list[j].content}')"><i class="scoicon sco-chat-fill" style="font-size: 1rem;"></i></a>` } let imageBox = "" let imageList = "" if (list[j].image) { const image = list[j].image for(let e = 0; e < image.length; e++){ imageList += `<img src="${image[e]}" title="即刻短文配图" />` } imageBox += `<div class="bber-content-img">${imageList}</div>` } let aplayer = "" if (list[j].aplayer) { aplayer = `<div class="bber-music"><meting-js server="${list[j].aplayer.server}" type="song" id="${list[j].aplayer.id}" mutex="true" preload="none" theme="var(--efu-main)" data-lrctype="0"></meting-js></div>` } let video = "" if (list[j].video) { if (list[j].video.player) { video = `<div class="bber-video"><video src="${list[j].video.player}" controls="controls" style="object-fit: cover;"></video></div>` } if (list[j].video.bilibili) { video = `<div class="bber-video"><iframe src="${list[j].video.bilibili}" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe></div>` } } let link = "" if (list[j].link) { link = `<a class="bber-content-link href="${list[j].link}" title="跳转到短文指引的链接"><i class="scoicon sco-link-m-line"></i>链接</a>` } if (style === 1) { listResult += ` <li class="item"> <div id="bber-content"> ${content} ${imageBox} </div> ${video} ${aplayer} <hr> <div class="bber-bottom"> <div class="bber-info"> <div class="bber-info-time"> <i class="scoicon sco-calendar-todo-fill"></i> <time class="datetime" datetime="${list[j].date}"></time> </div> ${link} </div> ${onclick} </div> </li>` } else if (style === 2) { listResult += ` <li class="item"> <div class="meta"> <img class="no-lightbox no-lazyload avatar" src="!{theme.aside.card.author.img}"> <div class="info"> <span class="bber_nick">#{config.author}</span> <time class="datetime bber_date" datetime="${list[j].date}"></time> </div> ${onclick} </div> <div id="bber-content"> ${content} ${imageBox} </div> ${video} ${aplayer} </li>` } else { console.log('请正确配置即刻样式!') } } says += `<ul id="waterfall" class="list">${listResult}</ul> ${saysTips}` } document.querySelector(".page-1").insertAdjacentHTML("afterbegin", says) changeTimeFormat() sco.reflashEssayWaterFall() sco.lazyloadImg() }) })()
动态Memos Memos的处理跟Json模式的处理大差不差,只是在Memos的content处理上有略微不同。将获取的数据被解析成JSON格式后,提供content的内容,将各个部分功能,如图片、音乐、视频等,以正则表达式的方式生成对应的结构,并将在原来content的内容里减去。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 ul.list#waterfall script. (()=>{ fetch("!{url_for(theme.says.mode_link)}").then(res => res.json()).then(data => { let items = [], html = '', strip = !{theme.says.strip}, saysTips = ''; if (strip === -1 || strip >= data.length) { data.forEach(item => { items.push(saysFormat(item)) }); saysTips = `<div id="bber-tips">- 已展开所有短文 -</div>` } else { data.slice(0, strip).forEach(item => { items.push(saysFormat(item)); }); saysTips = `<div id="bber-tips">- 只展示最近 ${strip} 条短文 -</div>` } document.getElementsByClassName('list')[0].innerHTML = items.map(item => item.content).join(''); document.querySelector(".page-1").insertAdjacentHTML("beforeend", saysTips) changeTimeFormat() sco.reflashEssayWaterFall() sco.lazyloadImg() }); function saysFormat(item) { let style = !{theme.says.style}, time = new Date(item.createdTs * 1000).toISOString().replace('Z', '+08:00'), content = item.content, image = content.match(/!\[.*\]\(.*?\)/g), aplayer = content.match(/{\s*music\s*(.*?)\s*(.*?)\s*}/g), player = content.match(/{\s*player\s*(.*)\s*}/g), bilibili = content.match(/{\s*bilibili\s*(.*?)\s*}/g), text = '', onclick = '', link = '', saysLink = '', saysContent = '', saysContents = ''; if (image) image = image.map(item => { return item.replace(/!\[.*\]\((.*?)\)/, '$1'); }); if (item.resourceList.length) { if (!image) image = []; item.resourceList.forEach(t => { if (t.externalLink) image.push(t.externalLink); else image.push(`{url}/o/r/${t.id}/${t.publicId}/${t.filename}`); }); } text = content.replace(/#(.*?)\s/g, '').replace(/\!\[(.*?)\]\((.*?)\)/g, '').replace(/\{(.*?)\}/g, ''); content = text.replace(/\[(.*?)\]\((.*?)\)/g, (match, p1, p2) => { link = p2; return ``; }); saysContent = `<p class="datacont">${content}</p>`; if (text) { onclick = `<a class="bber-reply goComment" ${content}><i class="scoicon sco-chat-fill" style="font-size:1rem"></i></a>` } if (image) { saysContent += `<div class="bber-content-img">`; image.forEach(e => saysContent += `<img src="${e}" title="即刻短文配图" />`); saysContent += '</div>'; } if (aplayer) aplayer.forEach(item => { const music = item.match(/{\s*music\s*(\S+)\s*(\S+)\s*}/); saysContents += `<div class="bber-music"><meting-js server="${music[1]}" type="song" id="${music[2]}" mutex="true" preload="none" theme="var(--efu-main)" data-lrctype="0"></meting-js></div>` }) if (player) player.forEach(item => { saysContents += `<div class="bber-video"><video src="${item.replace(/{\s*player\s*(.*)\s*}/, '$1')}" controls="controls" style="object-fit: cover;"></video></div>` }) if (bilibili) bilibili.forEach(item => { let bvid = item.match(/BV(\w+)/); saysContents += `<div class="bber-video"><iframe src="//player.bilibili.com/player.html?autoplay=0&bvid=BV${bvid[1]}" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"></iframe></div>` }) if (link) { saysLink = `<a class="bber-content-link href="${link}" title="跳转到短文指引的链接"><i class="scoicon sco-link-m-line"></i>链接</a>`; } if (style === 1) { return { content: ` <li class="item"> <div id="bber-content"> ${saysContent} </div> ${saysContents} <hr> <div class="bber-bottom"> <div class="bber-info"> <div class="bber-info-time"> <i class="scoicon sco-calendar-todo-fill"></i> <time class="datatime" datetime="${time}"></time> </div> ${saysLink} </div> ${onclick} </div> </li>` }; } else if (style === 2) { return { content: ` <li class="item"> <div class="meta"> <img class="no-lightbox no-lazyload avatar" src="!{theme.aside.card.author.img}"> <div class="info"> <span class="bber_nick">#{config.author}</span> <time class="datetime bber_date" datetime="${time}"></time> </div> ${onclick} </div> <div id="bber-content"> ${saysContent} </div> ${saysContents} </li>` }; } else { console.log('请正确配置即刻样式!') } } })()
即刻Mini 对于首页的即刻Mini这个模块,大致处理就是分为:获取数据,处理数据,生成HTML,并将部分数据缓存到本地存储。
通过Fetch API异步获取数据,再根据配置的显示模式(’json’或’memos’)进行不同的处理,主要是因为Memos的content需要用到正则去匹配处理,所以才分成了两套。
最后就将数据存储到本地缓存(十分钟过期),这一步仅仅只是为了减少请求量,对于一些公益服务所作出的改动。
PS:使用F12进行调试的同学应该会注意到,本地缓存里有个Solitude组,至今为止其内包含了封面主色(postcolor),以及现在的即刻Mini数据(says)。这里想说的一点就是,目前大多Hexo的主题所使用的本地缓存组都太多太多了,就如butterfly、anzhiy等都是使用的一级,在切换主题时难免会共用到相同的组,这就是我使用二级组的原因。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 script. (()=>{ function syasLocalCache() { const solitudeData = JSON.parse(localStorage.getItem('Solitude')); if (solitudeData && solitudeData.says) { const { value, expiration } = solitudeData.says; const currentTime = new Date().getTime(); if (expiration && currentTime < expiration) { const bberTalkContainer = document.getElementById('bber-talk'); if (bberTalkContainer) { bberTalkContainer.innerHTML = ''; value.forEach((item) => { const liElement = document.createElement('div'); liElement.className = 'li-style swiper-slide'; liElement.textContent = item; bberTalkContainer.appendChild(liElement); }); } } else { saysDynamic(); } } else { saysDynamic(); } } function saysDynamic() { fetch("!{url_for(theme.says.mode_link)}") .then(response => response.json()) .then(data => { var saysMode = '!{theme.says.mode}'; if (saysMode === 'json') { const saysList = data[0].essay_list; const saysStrip = saysList.slice(0, 10); saysStrip.forEach(says => { let content = says.content; if (says.image) { content += '【图片】'; } if (says.aplayer) { content += '【音乐】'; } if (says.video) { content += '【视频】'; } saysDeposit(content); }); } else if (saysMode === 'memos') { const saysStrip = data.slice(0, 10); saysStrip.forEach(says => { let content = says.content content = content.replace(/#说说/g, ''); content = content.replace(/!\[\]\((.*?)\)/g, '【图片】'); content = content.replace(/\{ music (.*?) \}/g, '【音乐】'); content = content.replace(/\{ bilibili (.*?) \}/g, '【视频】'); content = content.replace(/\{ player (.*?) \}/g, '【视频】'); saysDeposit(content); }); } syasLocalCache(); }) .catch(error => console.error('即刻mini | ', error)); } function saysDeposit(saysdata) { const groupName = 'Solitude'; const storedData = localStorage.getItem(groupName); const existingData = storedData ? JSON.parse(storedData) : {}; existingData.says = existingData.says || {}; existingData.says.value = existingData.says.value || []; existingData.says.value.push(saysdata); existingData.says.expiration = new Date().getTime() + 10 * 60 * 1000; localStorage.setItem(groupName, JSON.stringify(existingData)); } syasLocalCache(); })()
参考
引用站外链接
即刻短文页 | MeuiCat
属于私人的叨叨池,说你想说的;多种部署方式的iCat版动静态即刻短文
贡献
引用站外链接
Hexo-theme-solitude | GitHub
✨ feat:即刻短文新增动态模式