<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-cn"><generator uri="https://gohugo.io/" version="0.147.7">Hugo</generator><title type="html">有呀</title><link href="https://nuoea.com/tags/twikoo/" rel="alternate" type="text/html" title="html"/><link href="https://nuoea.com/tags/twikoo/index.xml" rel="alternate" type="application/rss+xml" title="rss"/><updated>2026-07-07T04:03:54+00:00</updated><id>https://nuoea.com/tags/twikoo/</id><entry><title type="html">Memos页面添加Twikoo评论系统</title><link href="https://nuoea.com/memos-twikoo/" rel="alternate" type="text/html"/><id>https://nuoea.com/memos-twikoo/</id><published>2023-06-05T21:56:31+08:00</published><updated>2023-06-05T21:56:31+08:00</updated><content type="html"><![CDATA[<h2 id="写在前面">写在前面</h2>
<p>如果没有木木老师的<a href="https://immmmm.com/memos-with-twikoo/">《Memos x Twikoo》</a>我是根本不会把这两个毫不相干的系统联系起来的，在给Memos添加了Twikoo评论系统之后，因为增加了社交属性，所以BB的时候，都更带劲了。</p>
<p>而美中不足的就是如果需要评论，需要跳转到Memos的页面内，这对于用户体验来说，还是略有不足的。而就在前不久，拾月老师的一篇<a href="https://www.skyue.com/23051422.html">《单页 Memos 添加 Artalk 评论，无限接近微博》</a>让评论系统嵌入Memos页面内，从而可以沉浸式边BB边吐槽，让Momos从一个记录工具成功变身微博、朋友圈，可玩性大增。只不过我看教程用的都是<code>Artalk</code>这个评论工具，作为用着<code>Twikoo</code>很顺手，并不想更换的我来说，只能自己根据大佬们提供的思路，自行折腾了。</p>
<h2 id="评论数量">评论数量</h2>
<p>关于Memos页面的搭建，直接用木木老师的就好。木木老师开发的版本，代码逻辑清晰，功能完善，开箱即用。Twikoo评论数量的实现在官网有相应API。</p>
<blockquote>
<p>批量获取文章评论数</p></blockquote>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#a6e22e">twikoo</span>.<span style="color:#a6e22e">getCommentsCount</span>({
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">envId</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;您的环境id&#39;</span>, <span style="color:#75715e">// 环境 ID
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>  <span style="color:#75715e">// region: &#39;ap-guangzhou&#39;, // 环境地域，默认为 ap-shanghai，如果您的环境地域不是上海，需传此参数
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>  <span style="color:#a6e22e">urls</span><span style="color:#f92672">:</span> [ <span style="color:#75715e">// 不包含协议、域名、参数的文章路径列表，必传参数
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#e6db74">&#39;/2020/10/post-1.html&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#39;/2020/11/post-2.html&#39;</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#e6db74">&#39;/2020/12/post-3.html&#39;</span>
</span></span><span style="display:flex;"><span>  ],
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">includeReply</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">false</span> <span style="color:#75715e">// 评论数是否包括回复，默认：false
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>}).<span style="color:#a6e22e">then</span>(<span style="color:#66d9ef">function</span> (<span style="color:#a6e22e">res</span>) {
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">console</span>.<span style="color:#a6e22e">log</span>(<span style="color:#a6e22e">res</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">// 返回示例: [
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>  <span style="color:#75715e">//   { url: &#39;/2020/10/post-1.html&#39;, count: 10 },
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>  <span style="color:#75715e">//   { url: &#39;/2020/11/post-2.html&#39;, count: 0 },
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>  <span style="color:#75715e">//   { url: &#39;/2020/12/post-3.html&#39;, count: 20 }
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>  <span style="color:#75715e">// ]
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>}).<span style="color:#66d9ef">catch</span>(<span style="color:#66d9ef">function</span> (<span style="color:#a6e22e">err</span>) {
</span></span><span style="display:flex;"><span>  <span style="color:#75715e">// 发生错误
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>  <span style="color:#a6e22e">console</span>.<span style="color:#a6e22e">error</span>(<span style="color:#a6e22e">err</span>);
</span></span><span style="display:flex;"><span>});
</span></span></code></pre></div><p>请求中，需要一个评论URL的数组，所以我的思路是先通过Api获取Memos的数据。在遍历获取到的数据之后，拿到我所希望的由URL组成的数组。</p>
<p>直接在 getFirstList（） 方法中增加一个方法 updateTiwkoo()，并传值。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">getFirstList</span>() {
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">bbUrl</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">memos</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;api/memo?creatorId=&#34;</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">bbMemo</span>.<span style="color:#a6e22e">creatorId</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;&amp;rowStatus=NORMAL&amp;limit=&#34;</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">limit</span>;
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">fetch</span>(<span style="color:#a6e22e">bbUrl</span>).<span style="color:#a6e22e">then</span>(<span style="color:#a6e22e">res</span> =&gt; <span style="color:#a6e22e">res</span>.<span style="color:#a6e22e">json</span>()).<span style="color:#a6e22e">then</span>(<span style="color:#a6e22e">resdata</span> =&gt; {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">updateTiwkoo</span>(<span style="color:#a6e22e">resdata</span>.<span style="color:#a6e22e">data</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">nowLength</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">resdata</span>.<span style="color:#a6e22e">data</span>.<span style="color:#a6e22e">length</span>
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">nowLength</span> <span style="color:#f92672">&lt;</span> <span style="color:#a6e22e">limit</span>) { <span style="color:#75715e">//返回数据条数小于 limit 则直接移除“加载更多”按钮，中断预加载
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>      document.<span style="color:#a6e22e">querySelector</span>(<span style="color:#e6db74">&#34;button.button-load&#34;</span>).<span style="color:#a6e22e">remove</span>()
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">return</span>
</span></span><span style="display:flex;"><span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">page</span><span style="color:#f92672">++</span>
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">offset</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">limit</span> <span style="color:#f92672">*</span> (<span style="color:#a6e22e">page</span> <span style="color:#f92672">-</span> <span style="color:#ae81ff">1</span>)
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">getNextList</span>()
</span></span><span style="display:flex;"><span>  });
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">updateTiwkoo</span>(<span style="color:#a6e22e">data</span>) {
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">twiID</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">data</span>.<span style="color:#a6e22e">map</span>((<span style="color:#a6e22e">item</span>) =&gt; <span style="color:#a6e22e">memos</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;m/&#34;</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">item</span>.<span style="color:#a6e22e">id</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#a6e22e">twikoo</span>.<span style="color:#a6e22e">getCommentsCount</span>({
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">envId</span><span style="color:#f92672">:</span> <span style="color:#a6e22e">envId</span>, <span style="color:#75715e">// 环境 ID
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    <span style="color:#a6e22e">urls</span><span style="color:#f92672">:</span> <span style="color:#a6e22e">twiID</span>,
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">includeReply</span><span style="color:#f92672">:</span> <span style="color:#66d9ef">true</span> <span style="color:#75715e">// 评论数是否包括回复，默认：false
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>  }).<span style="color:#a6e22e">then</span>(<span style="color:#66d9ef">function</span> (<span style="color:#a6e22e">res</span>) {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">updateCount</span>(<span style="color:#a6e22e">res</span>)
</span></span><span style="display:flex;"><span>  }).<span style="color:#66d9ef">catch</span>(<span style="color:#66d9ef">function</span> (<span style="color:#a6e22e">err</span>) {
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">console</span>.<span style="color:#a6e22e">error</span>(<span style="color:#a6e22e">err</span>);
</span></span><span style="display:flex;"><span>  });
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">function</span> <span style="color:#a6e22e">updateCount</span>(<span style="color:#a6e22e">res</span>) {
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">twiCount</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">res</span>.<span style="color:#a6e22e">map</span>((<span style="color:#a6e22e">item</span>) =&gt; {
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">return</span> Object.<span style="color:#a6e22e">assign</span>({},{<span style="color:#e6db74">&#39;count&#39;</span><span style="color:#f92672">:</span><span style="color:#a6e22e">item</span>.<span style="color:#a6e22e">count</span>})
</span></span><span style="display:flex;"><span>    });
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">bbTwikoo</span> <span style="color:#f92672">=</span> <span style="color:#a6e22e">data</span>.<span style="color:#a6e22e">map</span>((<span style="color:#a6e22e">item</span>,<span style="color:#a6e22e">index</span>) =&gt; {
</span></span><span style="display:flex;"><span>      <span style="color:#66d9ef">return</span> {...<span style="color:#a6e22e">item</span>, ...<span style="color:#a6e22e">twiCount</span>[<span style="color:#a6e22e">index</span>]};
</span></span><span style="display:flex;"><span>    });
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">updateHTMl</span>(<span style="color:#a6e22e">bbTwikoo</span>)
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>在获取到评论数的数据后，直接将两个数组合并。形成一个包含有评论数的新数组。</p>
<h2 id="评论内容">评论内容</h2>
<p>主要是在 <code>Memos</code> 页面内增加一个 供 <code>Twikoo</code> 初始化的容器。并通过一系列触发操作显示渲染。详细如下：</p>
<p>首先，我们需要在页面内增加一个按钮，通过点击来触发评论加载。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;<span style="color:#f92672">a</span> <span style="color:#a6e22e">onclick</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;loadTwikoo(memosId)&#39;</span>&gt;&lt;/<span style="color:#f92672">a</span>&gt;
</span></span></code></pre></div><p>其次，我们需要一个容纳 <code>Twikoo</code> 评论的容器，未触发时该容器隐藏。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-html" data-lang="html"><span style="display:flex;"><span>&lt;<span style="color:#f92672">div</span> <span style="color:#a6e22e">class</span><span style="color:#f92672">=</span><span style="color:#e6db74">&#39;twikoo-body twikoo-memosId d-none&#39;</span>&gt;&lt;/<span style="color:#f92672">div</span>&gt;
</span></span></code></pre></div><p>最后，我们需要一个点击事件，将评论初始化。</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#66d9ef">function</span> <span style="color:#a6e22e">loadTwikoo</span>(<span style="color:#a6e22e">memosId</span>) {
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">twikooDom</span> <span style="color:#f92672">=</span> document.<span style="color:#a6e22e">querySelector</span>(<span style="color:#e6db74">&#39;.twikoo-memosId&#39;</span>);
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">var</span> <span style="color:#a6e22e">twikooCon</span> <span style="color:#f92672">=</span> <span style="color:#e6db74">&#34;&lt;div id=&#39;twikoo&#39;&gt;&lt;/div&gt;&#34;</span>
</span></span><span style="display:flex;"><span>  <span style="color:#66d9ef">if</span> (<span style="color:#a6e22e">twikooDom</span>.<span style="color:#a6e22e">classList</span>.<span style="color:#a6e22e">contains</span>(<span style="color:#e6db74">&#39;d-none&#39;</span>)) {
</span></span><span style="display:flex;"><span>    document.<span style="color:#a6e22e">querySelectorAll</span>(<span style="color:#e6db74">&#39;.twikoo-body&#39;</span>).<span style="color:#a6e22e">forEach</span>((<span style="color:#a6e22e">item</span>) =&gt; {<span style="color:#a6e22e">item</span>.<span style="color:#a6e22e">classList</span>.<span style="color:#a6e22e">add</span>(<span style="color:#e6db74">&#39;d-none&#39;</span>);})
</span></span><span style="display:flex;"><span>    <span style="color:#66d9ef">if</span>(document.<span style="color:#a6e22e">getElementById</span>(<span style="color:#e6db74">&#34;twikoo&#34;</span>)){
</span></span><span style="display:flex;"><span>      document.<span style="color:#a6e22e">getElementById</span>(<span style="color:#e6db74">&#34;twikoo&#34;</span>).<span style="color:#a6e22e">remove</span>() <span style="color:#75715e">//如果页面中已经有其他Twikoo初始化，则移除。
</span></span></span><span style="display:flex;"><span><span style="color:#75715e"></span>    }
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">twikooDom</span>.<span style="color:#a6e22e">insertAdjacentHTML</span>(<span style="color:#e6db74">&#39;beforeend&#39;</span>, <span style="color:#a6e22e">twikooCon</span>); 
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">twikooDom</span>.<span style="color:#a6e22e">classList</span>.<span style="color:#a6e22e">remove</span>(<span style="color:#e6db74">&#39;d-none&#39;</span>);
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">twikoo</span>.<span style="color:#a6e22e">init</span>({
</span></span><span style="display:flex;"><span>      <span style="color:#a6e22e">envId</span><span style="color:#f92672">:</span> <span style="color:#a6e22e">envId</span>,
</span></span><span style="display:flex;"><span>      <span style="color:#a6e22e">el</span><span style="color:#f92672">:</span> <span style="color:#e6db74">&#39;#twikoo&#39;</span>,
</span></span><span style="display:flex;"><span>      <span style="color:#a6e22e">path</span><span style="color:#f92672">:</span> <span style="color:#a6e22e">memosPath</span> <span style="color:#f92672">+</span> <span style="color:#e6db74">&#34;/m/&#34;</span> <span style="color:#f92672">+</span> <span style="color:#a6e22e">memosId</span> 
</span></span><span style="display:flex;"><span>    });
</span></span><span style="display:flex;"><span>  }<span style="color:#66d9ef">else</span>{
</span></span><span style="display:flex;"><span>    <span style="color:#a6e22e">twikooDom</span>.<span style="color:#a6e22e">classList</span>.<span style="color:#a6e22e">add</span>(<span style="color:#e6db74">&#39;d-none&#39;</span>);
</span></span><span style="display:flex;"><span>    document.<span style="color:#a6e22e">getElementById</span>(<span style="color:#e6db74">&#34;twikoo&#34;</span>).<span style="color:#a6e22e">remove</span>()
</span></span><span style="display:flex;"><span>  }
</span></span><span style="display:flex;"><span>}
</span></span></code></pre></div><p>值得一提的是，需要将该 <code>Twikoo</code> 的ID值传给触发的方法。</p>
<h2 id="最终效果">最终效果</h2>
<p>效果如下</p>
<p><img class="lozad" data-src="https://i.nuoea.com/img/2023/06/05/1685976063.jpg" alt=""  /></p>]]></content><category scheme="https://nuoea.com/categories/%E6%8A%98%E8%85%BE" term="%E6%8A%98%E8%85%BE" label="折腾"/><category scheme="https://nuoea.com/tags/memos" term="memos" label="Memos"/><category scheme="https://nuoea.com/tags/twikoo" term="twikoo" label="Twikoo"/></entry></feed>