Hướng dẫn tạo tiện ích các bài đăng gần đây dưới chân bài viết

Tiện ích các bài đăng gần đây dưới chân bài viết là một phương pháp rất hay đối với một Blog được thiết kế với giao diện tin tức có nhiều bài viết. Tuy nhiên cách áp dụng lại không đơn giản vì bạn phải xác định được bố cục giao diện của Blog và chân bài viết. Mình giải thích hai thành phần này như sau:

1. Bố cục giao diện

- main-wrapper: nằm bên trái đây là vùng chứa tiện ích widget Blog1 (Bài viết) thường có độ rộng 70%
- sidebar-wrapper: nằm bên phải đây là vùng chứa các tiện ích thường có độ rộng 30%

Khi thiết kế reponsive cho giao diện ví dụ với màn hình hiển thị kích thước 800px phần main wrapper được thiết lập độ rộng 100% và sidebar-wrapper cũng thiết lập độ rộng 100% như vậy sidebar-wrapper sẽ nhảy xuống dưới phần main wrapper.

2. Chân bài viết

Tiện ích các bài đăng gần đây phải nằm ngay dưới chân của tiện ích widget Blog1, ví dụ ta có đoạn HTML hiển thị như sau:

Copy
<div class="main-wrapper" id="main" name="Phần chính của trang">
  <div class="widget Blog" data-version="2" id="Blog1">
    // Bài viết
  </div>
  <div class="widget HTML" data-version="2" id="HTML1">
    // Các bài đăng gần đây
  </div>
</div>
<div class="sidebar-wrapper" id="sidebar" name="Thanh bên">
  // Các tiện ích
</div>

Như vậy từ 1 và 2 chúng ta có thể suy ra được như sau: giả sử chúng ta có 3 mục A, B, C trong đó A là widget Blog1, B là widget các bài viết gần đây và C là vùng sidebar chứa các tiện ích

- Màn hình kích thước >800px các tiện ích này hiển thị như sau:

A    C
B

- Màn hình kích thước <800px các tiện ích này hiển thị như sau:

A
B
C

Điểm đặc biệt của tiện ích này có những đặc điểm nổi bật như sau:

- Tiện ích chỉ hiển thị các bài viết khi scroll thanh cuộn đến hết bài viết nên không ảnh hưởng đến tốc độ tải trang.
- Nếu trên màn hình có kích thước từ 800px trở lên sẽ tự động tải thêm các bài viết tiếp theo khi scroll thanh cuộn xuống dưới chân trang.
- Trên màn hình có kích thước 800px trở xuống sẽ hiển thị nút HIỂN THỊ THÊM ngay dưới chân bài viết cuối cùng của các bài viết gần đây.

Bây giờ chúng ta sẽ bắt đầu tạo tiện ích các bài đăng gần đây dưới chân bài viết theo các bước sau:

1. Thêm tiện ích HTML

Đăng nhập vào Blogger, chuyển đến phần Bố cục chọn thêm một tiện ích HTML/Javascript sau đó kéo tiện ích này vào ngay dưới tiện ích Bài đăng trên Blog.

2. Chỉnh sửa nội dung tiện ích

Vào Chủ đề, chỉnh sửa HTML chuyển đến tiện ích HTML vừa thêm ngoài Bố cục thêm dòng cond='data:view.isPost' ngay sau <b:widget ví dụ <b:widget cond='data:view.isPost' id='HTML1' locked='false' title='Bài mới' type='HTML' version='2' visible='true'> mục đích đặt điều kiện cho tiện ích này chỉ hiển thị trong bài viết

Tiếp tục mở rộng thẻ tag <b:includable id='main'> của tiện ích thay nội dung bên trong thành như sau:

Copy
<div class='recentposts'>
  <h3><span class='title'>Bài mới</span></h3>
  <ul class='recent-posts'></ul>
  <input class='load-posts hidden' type='button' value='Hiển thị thêm'/>
  <input id='numposts' type='hidden' value='0'/>
  <input id='allposts' type='hidden' value=''/>
  <div class='loadposts spinner hidden'/>
</div>

3. Tạo script hiển thị các bài đăng gần đây

Chèn đoạn sccript sau ngay trước thẻ đóng </body>

Copy
<b:if cond='data:view.isPost'>
<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js'></script>
<script>//<![CDATA[
function getPosts(e) {
  if (e.feed.entry) {
    for (var t = 0; t < e.feed.entry.length; t++) {
      for (var a = 0; a < e.feed.entry[t].link.length; a++)
        if ("alternate" == e.feed.entry[t].link[a].rel) {
          var s = e.feed.entry[t].link[a].href;
          break
        }
      for (var r = 0; r < e.feed.entry[t].category.length; r++) var l = e.feed.entry[t].category[r].term,
        n = "/search/label/" + l;
      var i, d = e.feed.entry[t].title.$t,
        p = e.feed.entry[t].published.$t,
        c = p.substring(8, 10) + " thag " + p.substring(5, 7) + ", " + p.substring(0, 4),
        x = e.feed.entry[t].summary.$t.substring(0, 150);
      try {
        i = e.feed.entry[t].media$thumbnail.url.replace("s72-c", "s320")
      } catch (e) {
        i = "https://4.bp.blogspot.com/-00O66C-eBQs/W0IcokXSnOI/AAAAAAAAL_k/g4KtDm7SkQsoe7_G0vZ_C_nU0Gf_-kyVQCLcBGAs/s1600/safe_image.png"
      }
      var w = e.feed.entry[t].media$thumbnail.url,
        w200 = w.replace("s72-c", "w200-h112-p-k-no-nu"),
        w320 = w.replace("s72-c", "w320-h180-p-k-no-nu"),
        w400 = w.replace("s72-c", "w400-h225-p-k-no-nu"),
        w640 = w.replace("s72-c", "w640-h360-p-k-no-nu"),
        w1600 = w.replace("s72-c", "w1600-h900-p-k-no-nu");
      $('.recent-posts').append('<li><div class="post-thumb"><a href=' + s + ' title="' + d + '"><img alt="' + d + '" src=' + i + '  sizes="(min-width: 954px) 842px, (min-width: 801px) calc(100vw - 112px), calc(100vw - 64px)" srcset="' + w200 + " 200w, " + w320 + " 320w, " + w400 + " 400w, " + w640 + " 640w, " + w1600 + ' 1600w"/></a></div><h2 class="post-title"><a href=' + s + ' title="' + d + '">' + d + '</a></h2><div class="post-meta"><span class="post-label"><a href="' + n + '" title="' + l + '">' + l + '</a></span><span class="post-date">' + c + '</span></div><p class="post-snippet">' + x + '</p></i>')
    }
  }
}
var content = false
$(document).on('scroll', function() {
  if ($(this).scrollTop() >= $('#HTML1').position().top) {
    if (!content) {
      content = true
      var numposts = 7;
      var mq = window.matchMedia('(max-width: 800px)');
      if (mq.matches) {
        $('.load-posts').removeClass('hidden')
        $.ajax({
          type: 'GET',
          url: '/feeds/posts/summary',
          data: {
            'max-results': numposts,
            'alt': 'json'
          },
          dataType: 'jsonp',
          jsonp: 'callback',
          jsonpCallback: 'getPosts',
          success: function(e) {
            var totalposts = e.feed.openSearch$totalResults.$t
            $('#allposts').attr('value', totalposts)
            $('.load-posts').click(function() {
              $('.loadposts').removeClass('hidden')
              var items = Number($('#numposts').val());
              items = items + numposts;
              if (items <= totalposts) {
                $('.load-posts').addClass('hidden')
                $('#numposts').val(items);
                setTimeout(function() {
                  $.ajax({
                    type: 'GET',
                    url: '/feeds/posts/summary',
                    data: {
                      'max-results': numposts,
                      'start-index': items + 1,
                      'alt': 'json'
                    },
                    dataType: 'jsonp',
                    jsonp: 'callback',
                    jsonpCallback: 'getPosts',
                    success: function() {
                      $('.load-posts').removeClass('hidden')
                      var lastposts = items + numposts;
                      if (lastposts > totalposts) {
                        $('.loadposts').addClass('hidden')
                      } else {
                        $('.loadposts').addClass('hidden')
                      }
                    }
                  })
                }, 500)
              }
            })
          }
        })
      } else {
        $.ajax({
          type: 'GET',
          url: '/feeds/posts/summary',
          data: {
            'max-results': numposts,
            'alt': 'json'
          },
          dataType: 'jsonp',
          jsonp: 'callback',
          jsonpCallback: 'getPosts',
          success: function(e) {
            var totalposts = e.feed.openSearch$totalResults.$t
            $('#allposts').attr('value', totalposts)
            scroll = 1
            $(window).scroll(function() {
              var a = $(window).scrollTop(),
                b = parseInt($(document).height() - $(window).height() - 200)
              if (a >= b) {
                if (scroll == 1) {
                  scroll = 0
                  $('.loadposts').removeClass('hidden')
                  var items = Number($('#numposts').val())
                  items = items + numposts
                  if (items <= totalposts) {
                    setTimeout(function() {
                      $('#numposts').val(items)
                      $.ajax({
                        type: 'GET',
                        url: '/feeds/posts/summary',
                        data: {
                          'max-results': numposts,
                          'start-index': items + 1,
                          'alt': 'json'
                        },
                        dataType: 'jsonp',
                        jsonp: 'callback',
                        jsonpCallback: 'getPosts',
                        success: function() {
                          scroll = 1
                          var lastposts = items + numposts;
                          if (lastposts > totalposts) {
                            $('.loadposts').addClass('hidden')
                          } else {
                            $('.loadposts').addClass('hidden')
                          }
                        }
                      })
                    }, 500)
                  } else {
                    $('.loadposts').addClass('hidden')
                  }
                }
              }
            })
          }
        })
      }
    }
  }
})
//]]></script>
</b:if>

Lưu ý:
  • #HTML1: là id của tiện ích
  • 7: Số bài viết hiển thị
  • 800px: điều kiện với màn hình 800px khi main-wrapper và sidebar-wrapper đều có độ rộng width:100%
  • 200: độ cao tính từ chân trang lên
4. Viết css cho giao diện các bài viết

Chèn trước thẻ đóng ]]></b:skin>

Copy
.recentposts {
    clear: both;
    float: left;
    position: relative;
}
.recentposts h3 {
    padding: 15px 0;
    color: #3c4043;
    font-size;16px;
    font-weight: bold;
    text-transform: uppercase;
    border-top: 2px solid rgba(0,0,0,0.12);
}
.recentposts h3 .title {
    border-top: 2px solid #1a73e8;
    padding: 15px 0 0 0;
}
.recentposts ul li {
    list-style: none;
    width: 100%;
    float: left;
    margin-bottom: 15px;
    padding-bottom: 15px;
    border-bottom: 1px solid rgba(0,0,0,0.12);
}
.recentposts ul li:last-child {
    padding: 0;
    border: 0;
}
.recentposts .post-thumb {
    width: 250px;
    position: relative;
    height: 145px;
    float: left;
    overflow: hidden;
    margin-right: 15px;
}
.recentposts .post-thumb img {
    float: left;
    width: 100%;
    height: 100%;
}
.recentposts .post-title {
    font-size: 22px;
    font-weight: bold;
    line-height: 26px;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
}
.recentposts a {
    color: #3c4043;
}
.recentposts .post-meta {
    padding: 10px 0;
    font-size: 15px;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}
.recentposts .post-date:before {
    content: '-';
    padding: 0 5px;
}
.recentposts .post-snippet {
    font-size: 15px;
    line-height: 1.6em;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
}
.recentposts .load-posts {
    border: 0;
    outline: 0;
    padding: 0;
    background: transparent;
    cursor: pointer;
    text-transform: uppercase;
    color: rgb(136,136,136);
    margin-top: 15px;
}
.recentposts .loadposts {
    position: relative;
    height: 150px;
    clear: both;
}
.recentposts .loadposts.hidden {
    display: none;
}
.recentposts .loadposts.spinner:before {
    content: '';
    box-sizing: border-box;
    position: absolute;
    top: 45%;
    left: 45%;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    border: 3px solid hsl(0,0%,53.3%);
    border-right-color: transparent;
    animation: spinner .9s linear infinite;
    -webkit-animation: spinner .9s ease-in-out infinite;
}
@keyframes spinner {
  to {
  transform:rotate(360deg);
}
}
@-webkit-keyframes spinner {
  to {
    -webkit-transform:rotate(360deg);
  }
}
@media (max-width:800px) {
  .recentposts .post-thumb {
    width: 250px;
    height: 145px;
  }
  .recentposts .post-meta {
    display: block;
  }
}
@media (max-width:500px) {
  .recentposts .post-thumb {
    width: 47%;
    height: 135px;
  }
  .recentposts .post-title {
    font-size: 18px;
    line-height: 1.4;
  }
  .recentposts .post-date {
    display: none;
  }
}
@media (max-width:414px) {
  .recentposts .post-thumb {
    height: 110px;
  }
  .recentposts .post-title {
    font-size: 16px;
    -webkit-line-clamp: 3;
  }
  .recentposts .post-meta {
    padding: 10px 0 0 0;
  }
  .recentposts .post-snippet {
    display:none;
  }
}
@media (max-width:384px) {
  .recentposts .post-thumb {
    height: 100px;
  }
}
@media (max-width:360px) {
  .recentposts .post-thumb {
    width: 50%;
  }
  .recentposts .post-title {
    line-height: 1.3;
  }
}
@media (max-width:320px) {
  .recentposts .post-thumb {
    height: 90px;
  }
  .recentposts .post-title {
    line-height: 1.3;
  }
}

KẾT LUẬN

Trước khi thêm tiện ích bạn phải đọc thật kỹ phần đầu bài và xác định đúng tiện ích nằm ở vị trí nào, tiếp theo bạn cần xác định ở kích thước nào thì phần main-wrapper và sidebar-wrapper sẽ được thiết lập độ rộng 100% giả sử trong template Blog bạn là 640px thì bạn phải thay 800px trong đoạn script thành 640px. Chấm hết bài!!!
Bài đăng mới hơn Bài đăng cũ hơn
Bài viết này có hữu ích không?