This site uses cookies for analytics, personalized content and ads. By continuing to browse this site, you agree to this use.
Author Image Thursday, 20 September 2018

Xây dựng hệ thống bình luận phân cấp blogger từ mã XML


Hệ thống bình luận của blogger thường nổi tiếng là nguyên nhân chính khiến trang của bạn bị chậm. Nguyên nhân chính do sự delay khá lâu từ phía server blogger khi load iframe thêm vào đó là một đống js (nếu bài có ít nhất 1 bình luận thì lượng js phải tải lên tới gần 500KB). Tuy nhiên sau khi đọc xong bài viết này bạn sẽ yêu thích nó hơn bao giờ hết

Với sự phối hợp linh hoạt từ mã XML, bạn hoàn toàn có thể load được iframe và lấy được nội dung bình luận từ cơ sở dữ liệu mà không cần dùng tới js.

Trong bài này tôi sẽ hướng dẫn bạn cách xây dựng hệ thống bình luận phân làm 2 cấp (hiện khá phổ biến trên các trang mạng xã hội)

Hệ thống bình luận blogger chia làm 2 phần
  • Phần viết bình luận (chính là cái iframe lâu la kia): sẽ được load cả trong trang bài viết có bình luận (threaded comment) cũng như bài viết không có bình luận
  • Phần hiển thị nội dung bình luận: chỉ hiển thị ở những bài viết có bình luận

Để phân cấp bình luận blogger cung cấp cho ta hàm inReplyTo giúp xác định gia phả bình luận, mỗi bình luận "cha" sẽ có một id để các bình luận "con" có thể chui vào

Theo như phân tích cấu trúc như trên code của tôi sẽ như sau

<b:includable id='hung1001Comments' var='post'>
    <div id='comments-holder'>
        <div class='comments-form'>
            <!-- Phần viết bình luận -->
        </div>
        <b:if cond='data:post.numberOfComments gt 0'>
            <div class='comment-thread'>
                <!-- Phần hiển thị các bình luận đã xuất bản -->
            </div>
        </b:if>
    </div>
</b:includable>

Phần viết bình luận sẽ bao gồm code của iframe, phần hiển thị bình luận sẽ được viết tiếp như sau

<div class='comment-thread'>
    <b:loop values='data:post.comments' var='commentLevel1'>
        <b:if cond='!data:commentLevel1.inReplyTo'>
            <div class='level1'>
                <!-- Lấy dữ liệu hiển thị cho bình luận level 1 -->
                <b:loop values='data:post.comments' var='commentLevel2'>
                    <b:if cond='data:commentLevel2.inReplyTo == data:commentLevel1.id'>
                        <div class='level2'>
                            <!-- Lấy dữ liệu hiển thị cho bình luận level 2 -->
                        </div>
                    </b:if>
                </b:loop>
            </div>
        </b:if>
    </b:loop>
</div>

Cứ lặp như vậy bạn có thể xây dựng hệ thống bình luận hiển thị theo nhiều cấp độ. FontAwesome sử dụng trong bài viết v5


Viết css cơ bản

.level1{margin: 0 0 1em}
.level2{margin: 0 0 0 40px}
.comments-form>h4{padding: 0 0 0 4px;letter-spacing: .02rem;font-size: 16px;margin:1em 0 0}
.comment-thread{font-family:arial,sans-serif;font-size:15px}
.comment-header{clear:both}
.comment-avatar img{border-radius:100%;width:35px;float:left;height:35px;margin:0 13px 0 0}
.comment-date{font-size:14px;margin:0 0 6px}
.comment-author a{font-weight:bold;color:#000}
.comment-content{padding:0 0 0 47px;margin:0 0 15px;line-height:1.4}
.comment-author,.comment-date{position:relative;display:block}
.comment-reply{color:#313131;text-decoration:none;font-size:12px;font-family:arial,sans-serif;font-weight:bold;display:inline-block;margin:0 0 10px;cursor:pointer}

Dữ liệu hiển thị tôi lấy sẽ bao gồm ảnh đại diện, người bình luận, thời gian bình luận và nội dung bình luận. Nếu bạn muốn thêm gì nữa thì tùy miễn là đúng thẻ gọi dữ liệu. Tham khảo bài viết Thẻ gọi dữ liệu tiện ích bài đăng Blog1

Với widget Blog1 v2


Đăng kí mới 1 thẻ b:includable

<b:includable id='hung1001Comments' var='post'>
    <div id='comments-holder'>
        <div class='comments-form'>
            <h4><i class='fas fa-pen-nib' /> <data:messages.postAComment/></h4>
            <iframe allowtransparency='true' class='blogger-iframe-colorize blogger-comment-from-post' expr:src='&quot;https://www.blogger.com/comment-iframe.g?blogID=&quot; + data:blog.blogId + &quot;&amp;&quot; + (data:view.isPost ? &quot;postID&quot; : &quot;pageID&quot;) + &quot;=&quot; + data:post.id + &quot;&amp;skin=soho&quot;' frameborder='0' id='comment-editor' name='comment-editor' width='100%' />
        </div>
        <b:if cond='data:post.numberOfComments gt 0'>
            <div class='comment-thread'>
                <b:loop values='data:post.comments' var='commentLevel1'>
                    <b:if cond='!data:commentLevel1.inReplyTo'>
                        <div class='level1'>
                            <div class='comment-header'>
                                <span class='comment-avatar'><img expr:src='resizeImage(data:commentLevel1.authorPhoto.url, 35, &quot;1:1&quot;)'/></span>
                                <span class='comment-author'><a expr:href='data:commentLevel1.authorUrl'><data:commentLevel1.author/></a></span>
                                <span class='comment-date' expr:title='data:commentLevel1.timestamp'><data:commentLevel1.timestamp/></span>
                            </div>
                            <div class='comment-content'>
                                <data:commentLevel1.body/>
                            </div>
                            <div class='comment-action'>
                                <a class='comment-reply' expr:data-href='&quot;https://www.blogger.com/comment-iframe.g?blogID=&quot; + data:blog.blogId + &quot;&amp;&quot; + (data:view.isPost ? &quot;postID&quot; : &quot;pageID&quot;) + &quot;=&quot; + data:post.id + &quot;&amp;parentID=&quot; + data:commentLevel1.id + &quot;&amp;skin=soho&quot;' href='javascript:void(0)'>REPLY</a>
                            </div>
                            <b:loop values='data:post.comments' var='commentLevel2'>
                                <b:if cond='data:commentLevel2.inReplyTo == data:commentLevel1.id'>
                                    <div class='level2'>
                                        <div class='comment-header'>
                                            <span class='comment-avatar'><img expr:src='resizeImage(data:commentLevel2.authorPhoto.url, 35, &quot;1:1&quot;)'/></span>
                                            <span class='comment-author'><a expr:href='data:commentLevel2.authorUrl'><data:commentLevel2.author/></a></span>
                                            <span class='comment-date' expr:title='data:commentLevel2.timestamp'><data:commentLevel2.timestamp/></span>
                                        </div>
                                        <div class='comment-content'>
                                            <data:commentLevel2.body/>
                                        </div>
                                    </div>
                                </b:if>
                            </b:loop>
                        </div>
                    </b:if>
                </b:loop>
            </div>
            <script type='text/javascript'>
                //<![CDATA[
                $(".comment-reply").each(function() {
                    $(this).on("click", function(t) {
                        t.preventDefault(), $("#comment-editor")[0].src = $(this).attr("data-href"), $(this).parents(".level1").append($(".comments-form")[0])
                    })
                });
                //]]>
            </script>
        </b:if>
    </div>
</b:includable>

Trong đó bạn cần đặc biệt lưu ý thằng này + &quot;&amp;skin=soho&quot; (xuất hiện 2 lần).
  • Nếu bạn xóa nó đi khung viết bình luận trở về v1. 
  • Nếu bạn thêm vào nhưng trong b:skin và <html chưa khai báo nó sẽ phụt ra error
  • Nếu bạn đã update comment form lên v2 và sửa đúng tên skin (chữ màu đỏ) nó sẽ hiển thị đúng theo ý muốn (các skin bao gồm soho, contempo, emporio)
  • Bạn nên nâng comment form lên v2 cho nó đồng bộ, xem bài viết Cập nhật blogger comment form lên version 2 thành công 100%

Như vậy đã hoàn thành xong phần định nghĩa hàm hiển thị khung viết bình luận và khung hiển thị bình luận, giờ là gọi ra sử dụng

Tìm đoạn mã

<b:include cond='data:view.isSingleItem' data='post' name='commentPicker'/>

và sửa thành

<b:include cond='data:view.isSingleItem' data='post' name='hung1001Comments'/>

Bạn có thể thoải mái thay đổi id của thẻ includable, miễn sao nó là duy nhất và định nghĩa như nào thì gọi đúng như vậy

Do định nghĩa và gọi hàm sử dụng bằng 1 thẻ hoàn toàn khác nên bạn yên tâm có thể quay về hệ thống bình luận cũ bất kì lúc nào

Với widget Blog1 v1 


Định nghĩa 1 thẻ b:includable

<b:includable id='hung1001Comments' var='post'>
    <div id='comments-holder'>
        <div class='comments-form'>
            <h4><i class='fas fa-pen-nib' /> <data:postCommentMsg/></h4>
            <iframe allowtransparency='true' class='blogger-iframe-colorize blogger-comment-from-post' expr:src='&quot;https://www.blogger.com/comment-iframe.g?blogID=&quot; + data:blog.blogId + &quot;&amp;&quot; + (data:view.isPost ? &quot;postID&quot; : &quot;pageID&quot;) + &quot;=&quot; + data:post.id + &quot;&amp;skin=soho&quot;' frameborder='0' id='comment-editor' name='comment-editor' width='100%' />
        </div>
        <b:if cond='data:post.numComments gt 0'>
            <div class='comment-thread'>
                <b:loop values='data:post.comments' var='commentLevel1'>
                    <b:if cond='!data:commentLevel1.inReplyTo'>
                        <div class='level1'>
                            <div class='comment-header'>
                                <span class='comment-avatar'><img expr:src='resizeImage(data:commentLevel1.authorPhoto.url, 35, &quot;1:1&quot;)'/></span>
                                <span class='comment-author'><a expr:href='data:commentLevel1.authorUrl'><data:commentLevel1.author/></a></span>
                                <span class='comment-date' expr:title='data:commentLevel1.timestamp'><data:commentLevel1.timestamp/></span>
                            </div>
                            <div class='comment-content'>
                                <data:commentLevel1.body/>
                            </div>
                            <div class='comment-action'>
                                <a class='comment-reply' expr:data-href='&quot;https://www.blogger.com/comment-iframe.g?blogID=&quot; + data:blog.blogId + &quot;&amp;&quot; + (data:view.isPost ? &quot;postID&quot; : &quot;pageID&quot;) + &quot;=&quot; + data:post.id + &quot;&amp;parentID=&quot; + data:commentLevel1.id + &quot;&amp;skin=soho&quot;' href='javascript:void(0)'>REPLY</a>
                            </div>
                            <b:loop values='data:post.comments' var='commentLevel2'>
                                <b:if cond='data:commentLevel2.inReplyTo == data:commentLevel1.id'>
                                    <div class='level2'>
                                        <div class='comment-header'>
                                            <span class='comment-avatar'><img expr:src='resizeImage(data:commentLevel2.authorPhoto.url, 35, &quot;1:1&quot;)'/></span>
                                            <span class='comment-author'><a expr:href='data:commentLevel2.authorUrl'><data:commentLevel2.author/></a></span>
                                            <span class='comment-date' expr:title='data:commentLevel2.timestamp'><data:commentLevel2.timestamp/></span>
                                        </div>
                                        <div class='comment-content'>
                                            <data:commentLevel2.body/>
                                        </div>
                                    </div>
                                </b:if>
                            </b:loop>
                        </div>
                    </b:if>
                </b:loop>
            </div>
            <script type='text/javascript'>
                //<![CDATA[
                $(".comment-reply").each(function() {
                    $(this).on("click", function(t) {
                        t.preventDefault(), $("#comment-editor")[0].src = $(this).attr("data-href"), $(this).parents(".level1").append($(".comments-form")[0])
                    })
                });
                //]]>
            </script>
        </b:if>
    </div>
</b:includable>

Phần skin tương tự như phần Blog1 v2

Cuối cùng là gọi ra để sử dụng

Tìm đoạn mã

<b:include cond='data:blog.pageType in {&quot;static_page&quot;,&quot;item&quot;}' data='post' name='comment_picker'/>

và sửa thành

<b:include cond='data:blog.pageType in {&quot;static_page&quot;,&quot;item&quot;}' data='post' name='hung1001Comments'/>
Lưu mẫu lại và kiểm tra thành quả

Chưa đến 3 dòng js đã xây dựng xong hệ thống bình luận phân cấp, rất ngầu đúng không ! với phương pháp này thì kể cả những người khó tính nhất cũng khó lòng mà không sử dụng lại blogger comment được

Như vậy bạn có thể thấy, chỉ cần chịu khó mày mò tìm hiểu về blogger code bạn có thể làm được tất cả những gì mình muốn.

Để lại bình luận nếu bạn gặp khó khăn và chúc thành công !
Comments:
Bạn được tự do bày tỏ quan điểm nhưng nghiêm cấm spam
  • Chèn ảnh theo mẫu [img]link[/img]
  • Chèn video Youtube theo mẫu [youtube]link[/youtube]
  • Chèn code theo mẫu [pre]code[/pre]. Lưu ý: mã hóa code trước khi bình luận

  • Please wait while i am loading Facebook SDK js