Thêm đoạn mã sau vào kịch bản tùy chỉnh 2 - j88vip1

Mục lục

Tiếp nối bài trước Sử dụng Memos để xây dựng mạng xã hội độc lập, bộ ba self-host đã hoàn thiện. Bài viết này sẽ hướng dẫn:

  1. Thêm bình luận Artalk vào ứng dụng Memos
  2. Tích hợp Memos đơn trang vào Typecho và thêm bình luận Artalk

Thêm bình luận Artalk vào ứng dụng Memos

Trước tiên, bạn cần tự triển khai dịch vụ keo bong da bình luận Artalk, có thể tham khảo tài liệu chính thức.

Tiếp theo, trong phần Cài đặt - Hệ thống của Memos, thêm kiểu tùy chỉnh và kịch bản tùy chỉnh.

  1. Thêm đoạn mã sau vào kịch bản tùy chỉnh:
// Bình luận Artalk
// CSS
document.head.innerHTML += '<link rel="stylesheet" href="...">';
// JS
function addArtalkJS() { 
  var memosArtalk = document.createElement("script");
  memosArtalk.src = "...";
  var artakPos = document.getElementsByTagName("script")[0];
  artakPos.parentNode.insertBefore(memosArtalk, artakPos);
};

function startArtalk() {
  start = setInterval(function(){
    var artalkDom = document.getElementById('Comments') || '';
    var memoAt = document.querySelector('.memo-wrapper') || ''; 
    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 = "Đang tải bình luận...";
    }

    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: '...',
            site: 'Tháng Mười Weibo',
            darkMode: 'auto'
          });
          Artalk.on('list-loaded', function() {
            memoLoading.innerHTML = ''
            startArtalk();
          });
        }, 1000);
      }
    }
  }, 1000)
}
startArtalk();
  1. Thêm đoạn mã sau vào kiểu tùy chỉnh:
a.time-text:after { content: ' Bình luận 💬 '; }
.atk-main-editor { margin-top: 20px; }

Tích hợp Memos đơn trang vào Typecho và thêm bình luận

Dưới đây là kết quả tích hợp:

Một số ví dụ về ứng dụng Memos đơn trang có trên internet, như phiên bản do thầy Mộc phát triển mà tôi đã sử dụng trong một thời gian.

Blog của tôi được xây dựng bằng Typecho, có máy chủ phía sau. Lần này tôi trực tiếp tạo một tệp mẫu memos.php trong thư mục chủ đề (tôi đang dùng chủ đề mặc định), và lấy dữ liệu Memos từ máy chủ để hiển thị.

Mã nguồn như sau:

<?php $this->need('header.php'); ?>
<div class="col-mb-12 col-8" id="main" role="main">
<article class="post"><h2 class="post-title"></h2><article>
<?php
$url = '...';
$ch = curl_init(); 
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); 
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 'Lỗi tải Weibo';
} 
curl_close($ch);

$array_data = json_decode($response,true)['data'];
foreach ($array_data as $obj) {
  if(time() - $obj['createdTs'] < 2592000){
    $memo_id = $obj['id'];
    $content = $obj['content'];
    $create_time = date('Y-m-d [rw88](/news/c87697a29d35a92a/)  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);
    
    $body_html = sprintf('<div class="memo-top-wrapper">Tháng Mười · %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">';
      foreach ($resources as $resource){
        $image_html .= sprintf('<img src="%s" decoding="async" loading="lazy">', $resource['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.'">Bình luận</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.'">Bình luận</span>(<span id="ArtalkCount" data-page-key="/m/'.$memo_id.'"></span>)</a><div style="display: none;" id="memo_'.$memo_id.'"></div></article>';
    }
  }
}
?>
<div class="memo-bottom">Xem thêm tại trang chính Weibo</div>
</div>

<link href="..." rel="stylesheet">
<script src="..."></script>

<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 = 'Thu gọn bình luận';
    new Artalk({
      el: '#memo_' + memo_id,
      pageKey: '/m/'+memo_id,
      pageTitle: 'Tháng Mười Weibo',
      server: '...',
      site: 'Tháng Mười Weibo',
    });
  }
  else{
    commentDiv.style.display='none';
    commentBtn.innerHTML = 'Bình luận';
  }
}
</script>

<script>
Artalk.loadCountWidget({
 server: '...',
 site:  'Tháng Mười Weibo',
 pvEl:  '#ArtalkPV',
 countEl: '#ArtalkCount',
});
</script>

<?php $this->need('footer.php'); ?>

Mã này thực hiện hai chức năng:

  1. Lấy dữ liệu Memos thông qua API và hiển thị trực tiếp trên máy chủ.
  2. Cung cấp hai đoạn mã JavaScript, một để hiển thị số lượng bình luận, một để mở và đóng hộp bình luận.

Đối với blog Typecho, mã trên có thể hoạt động tốt, chỉ cần điều chỉnh địa chỉ API Memos và hai tham số serversite trong hàm loadArtalk.

Một số điểm quan trọng:

  1. Mỗi memo có một container div với ID memo_{memo_id}, ví dụ <div id="memo_1"></div>, dùng để tải hộp bình luận.
  2. Nút “Bình luận” có thuộc tính onclick gọi hàm loadArtalk với tham số memo_id. Hàm này tìm container tương ứng, tải hộp bình luận và hiển thị bình luận cho memo đó. Nhấn lại sẽ thu gọn.
  3. Số lượng bình luận hiển thị nhờ thẻ <span id="ArtalkCount" data-page-key="/m/'.$memo_id.'"></span>.

Thêm các kiểu sau vào file style.css của chủ đề:

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;
}

Toàn bộ quá trình này đã khiến tôi mất ngủ đến 4 giờ sáng thứ Bảy, nhưng may mắn có ChatGPT hỗ trợ.

Một số điểm chưa hoàn hảo:

  1. Hình ảnh hiện tại được hiển thị dọc, chưa làm thành lưới 9 ô.
  2. Chưa có trang chi tiết, khi mở liên kết từ thông báo bình luận vẫn dẫn đến memos.skyue.com.

Tôi sẽ cố gắng giải quyết hai vấn đề này khi có thời gian, đặc biệt là vấn đề thứ hai. Rất mong muốn hiển thị trang chi tiết Memos ngay trên www.skyue.com, kỹ thuật chắc chắn khả thi, chỉ là tôi chưa nắm rõ cách thực hiện.