Tạo tiện ích nhận xét gần đây sử dụng button click và tự động tải thêm nhận xét khi scroll

Bài này mình bổ sung thêm hai diểm mới từ bài Hướng dẫn tạo tiện ích nhận xét gần đây sử dụng nút click mà mình đã viết trong Blog đó là khi click vào button mới tải feeds và khi kéo thanh cuộn xuống xẽ tự động tải thêm các nhận xét tiếp theo.

Phương pháp này có những ưu điểm sau:

- Thứ nhất không làm ảnh hưởng đến thời gian tải trang vì feeds không được tải chỉ khi nào click vào nút mới tải feeds
- Ưu điểm thứ hai là khi kéo thanh cuộn đến nhận xét cuối cùng sẽ tự động tải thêm các nhận xét tiếp theo. Lấy ví dụ thiết lập số nhận xét là 10 và khi click và nút sẽ tải feeds hiển thị 10 nhận xét và khi kéo thanh cuộn đến nhận xét thứ 10 sẽ tự động tải thêm 10 nhận xét tiếp theo tiếp tục keo thanh cuộn đến nhận xét 20 sẽ tải thêm 10 nhận xét tiếp theo. Cứ như vậy cho đến khi tải đến nhận xét cuối cùng khi kéo thanh cuộn
- Thứ ba thay thế ký tự viết tắt bằng biểu tượng cảm xúc

Phương pháp làm như sau:

<head>
<style type='text/css'>
button.open {
    background: transparent;
    border: none;
    cursor: pointer;
    margin: 0;
    padding: 8px;
    outline: none;
}
button.open:hover{
    background:rgb(230,230,230);
    border-radius:100%;
}
button.open svg {
    height: 24px;
    width: 24px;
    min-width: 24px;
    fill: hsl(0,0%,53.3%);
    vertical-align: text-bottom;
}
.recent-comments {
    padding: 10px;
    height: 456px;
    overflow-y: scroll;
    position: absolute;
    top: 50px;
    right: 0;
    left: 0;
    background: #fafafa;
    display: none;
    z-index: 9;
    max-width: 320px;
    width: 100%;
    box-shadow: 0 16px 24px 2px rgba(0,0,0,0.14), 0 6px 30px 5px rgba(0,0,0,0.12), 0 8px 10px -5px rgba(0,0,0,0.4);
}
.recent-comments .loading.load {
    position:relative;
    height:100px;
}
.recent-comments.spinner:before {
    top:47%;
    left:45%
}
.recent-comments.load{
    height:450px;
    position:relative
}
.recent-comments .loading.spinner:before {
    top:40%;left:45%
}
.spinner:before {
    content:'';
    box-sizing:border-box;
    position:absolute;
    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);
  }
}
.recent-comments::-webkit-scrollbar-track {
    border-radius:10px;
    background-color:#f0f1f5;
}
.recent-comments::-webkit-scrollbar {
    width:8px;
    background-color:#F5F5F5
}
.recent-comments::-webkit-scrollbar-thumb {
    border-radius:10px;
    background-color:hsla(0,0%,53.3%,.4)
}
.recent-comments li {
    list-style-type: none;
    position: relative;
    padding: 0 0 10px 0;
}
.recent-comments li:last-child {
    padding: 0;
}
.recent-comments .rc_avatar {
    position: absolute;
    border-radius: 50%;
    height: 40px;
    width: 40px;
    overflow: hidden;
}
.recent-comments .rc_avatar img {
    width: 100%;
    height: 100%;
}
.recent-comments .rc_block {
    background: rgb(230,230,230);
    padding: 10px;
    margin: 0 0 0 50px;
    border: 1px solid rgb(230,230,230);
    border-radius: 2px;
    display: block;
    font-size: 15px;
    line-height: 1.6;
}
.recent-comments .rc_block:before {
    content: '';
    width: 0;
    height: 0;
    position: absolute;
    top: 0;
    left: -18px;
    border-width: 10px;
    border-style: solid;
    border-color: rgb(230,230,230) rgb(230,230,230) transparent transparent;
    display: block;
    margin-left: 55px;
}
.recent-comments .rc_header {
    overflow: hidden;
    white-space: nowrap;
}
.recent-comments .rc_date {
    font-size: 13px;
    padding-left: 7px;
}
.recent-comments .rc_date a {
    color: #777;
}
.recent-comments .rc_content {
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
</style>
<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js'></script>
</head>
<body>
<button class='open' expr:title='data:messages.comments'>
  <svg viewBox='0 0 24 24'><path d='M12,2C6.5,2,2,6.5,2,12c0,5.5,4.5,10,10,10s10-4.5,10-10C22,6.5,17.5,2,12,2z M12,18c-0.6,0-1-0.5-1-1h2 C13,17.5,12.5,18,12,18z M17,16H7v-0.6l1.2-1.2v-3c0-1.9,1-3.4,2.8-3.8V6.9C11.1,6.4,11.5,6,12,6s0.9,0.4,0.9,0.9v0.4 c1.8,0.4,2.8,2,2.8,3.8v3l1.2,1.2V16z'/></svg>
</button>
<div class='recent-comments'>
  <ul class='comments'/>
  <div class='loading'/>
  <input id='numcomments' type='hidden' value='0'/>
  <input id='allcomments' type='hidden' value=''/>
</div>
<script>//<![CDATA[
$("button.open").click(function(e) {
  e.preventDefault()
  $(".recent-comments").toggle()
})
$('.recent-comments').click( function(e) {
  e.stopPropagation()
})
$('html').click(function() {
  $(".recent-comments").hide()
  $('.recent-comments ul').empty()
  $('#numcomments').attr('value', '0')
  $('#allcomments').attr('value', '')
  $('.loading').removeClass('spinner').removeClass('load')
})
$('button.open').on('click', function() {
  if ($('.recent-comments').css('display') === 'none') {
    $('.recent-comments').addClass('spinner')
    var numcomments = 10;
    $.ajax({
      type: 'GET',
      url: '/feeds/comments/summary',
      data: {
        'max-results': numcomments,
        'alt': 'json'
      },
      dataType: 'jsonp',
      jsonp: 'callback',
      jsonpCallback: 'getComments',
      success: function(e) {
        $('.recent-comments').removeClass('spinner')
        var totalcomments = e.feed.openSearch$totalResults.$t
        $('#allcomments').attr('value', totalcomments)
        scroll = 1
        $('.recent-comments').scroll(function() {
          var a = $('.recent-comments').scrollTop(),
            b = parseInt($('.comments').height() - $('.recent-comments').height())
          if (a >= b) {
            if (scroll == 1) {
              scroll = 0
              $('.loading').addClass('spinner').addClass('load')
              var items = Number($('#numcomments').val())
              items = items + numcomments
              if (items <= totalcomments) {
                setTimeout(function() {
                  $('#numcomments').val(items)
                  $.ajax({
                    type: 'GET',
                    url: '/feeds/comments/summary',
                    data: {
                      'max-results': numcomments,
                      'start-index': items + 1,
                      'alt': 'json'
                    },
                    dataType: 'jsonp',
                    jsonp: 'callback',
                    jsonpCallback: 'getComments',
                    success: function() {
                      scroll = 1
                      var lastcomments = items + numcomments;
                      if (lastcomments > totalcomments) {
                        $('.loading').removeClass('spinner').removeClass('load')
                      }
                    }
                  })
                }, 1000)
              } else {
                $('.loading').removeClass('spinner').removeClass('load')
              }
            }
          }
        })
      }
    })
  } else {
    $('.recent-comments ul').empty()
    $('#numcomments').attr('value', '0')
    $('#allcomments').attr('value', '')
    $('.loading').removeClass('spinner').removeClass('load')
  }
})
function getComments(e) {
  if (e.feed.entry) {
    for (var t = 0; t < e.feed.entry.length; t++) {
      for (var r = 0; r < e.feed.entry[t].link.length; r++)
        if ("alternate" == e.feed.entry[t].link[r].rel) {
          var a = e.feed.entry[t].link[r].href;
          break
        }
      var n = e.feed.entry[t].published.$t,
        l = e.feed.entry[t].author[0].gd$image.src.replace("https://img1.blogblog.com/img/blank.gif", "https://4.bp.blogspot.com/-5EiQyVV8RQw/W0cWvhABRlI/AAAAAAAAMBo/lUUVZpG42SAj64m5GQJ-iBFY5YYlHD_uQCLcBGAs/s1600/blogger-icon.png"),
        s = n.substring(8, 10) + " thag " + n.substring(5, 7) + ", " + n.substring(0, 4),
        i = e.feed.entry[t].author[0].uri.$t,
        c = (e.feed.entry[t].title.$t, e.feed.entry[t].author[0].name.$t),
        o = e.feed.entry[t].summary.$t.substring(0, 150);
      function formatUrl(o) {
        if (o) {
          o = o.replace(/((https?\:\/\/)|(www\.))(\S+)(\w{2,4})(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/gi, function(url) {
            var full_url = url;
            if (!full_url.match('^https?:\/\/')) {
              full_url = 'http://' + full_url;
            }
            return '<a href="' + full_url + '">' + url + '</a>';
          });
        }
        return o;
      }
      $(".recent-comments ul").append('<li><div class="rc_avatar"><img src=' + l + ' alt="' + c + '" /></div><div class="rc_block"><div class="rc_header"><span class="rc_user"><a rel="nofollow" href=' + i + ' title="' + c + '" target="_blank">' + c + '</a></span><span class="rc_date"><a rel="nofollow" href=' + a + '>' + s + '</a></span></div><p class="rc_content">' + formatUrl(o) + "</p></div></li>")
    }
  }
  function replaceText() {
    bodyText = document.getElementsByClassName('recent-comments')[0]
    text = bodyText.innerHTML
    text = text.replace(/=ok/gi, '👌')
    text = text.replace(/=hi/gi, '✌')
    text = text.replace(/\(y\)/gi, '👍')
    text = text.replace(/\(yy\)/gi, '👎')
    text = text.replace(/=hl/gi, '👈')
    text = text.replace(/=hr/gi, '👉')
    text = text.replace(/=hup/gi, '👆')
    text = text.replace(/=hd/gi, '👇')
    text = text.replace(/=j/gi, '👇')
    text = text.replace(/=clap/gi, '👏')
    text = text.replace(/&lt;3/gi, '💗')
    text = text.replace(/=he/gi, '😍')
    text = text.replace(/:3/gi, '😂')
    text = text.replace(/:\)\)/gi, '😅')
    text = text.replace(/;\)/gi, '😉')
    text = text.replace(/:D/gi, '😁')
    text = text.replace(/=D/gi, '😃')
    text = text.replace(/:\)/gi, '🙂')
    text = text.replace(/\/\=r/gi, '😏')
    text = text.replace(/:\(\(/gi, '😭')
    text = text.replace(/:\(/gi, '😞')
    text = text.replace(/==/gi, '😓')
    text = text.replace(/:\*/gi, '😘')
    text = text.replace(/\^\_\^/gi, '😊')
    text = text.replace(/:\-\P/gi, '😛')
    text = text.replace(/:P/gi, '😜')
    text = text.replace(/\/=l/gi, '😒')
    text = text.replace(/:v/gi, '😬')
    text = text.replace(/\:\-\)/gi, '😌')
    text = text.replace(/8\-\)/gi, '🤓')
    text = text.replace(/8\|/gi, '😎')
    text = text.replace(/:\\/gi, '😕')
    text = text.replace(/:\'\(/gi, '😢')
    bodyText.innerHTML = text
  }
  replaceText()
}
//]]></script>
</body>

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?