Django多級評論(下)
上一篇文章django多級評論(上)講了多級評論後台部分的代碼,這篇文章則更側重於前端。
6、Ajax獲取評論數據
AJAX = 非同步 JavaScript 和 XML(Asynchronous JavaScript and XML)。簡短地說,就是在不重載整個網頁的情況下,AJAX 通過後台載入數據,並在網頁上進行顯示。jQuery 提供多個與 AJAX 有關的方法,通過 jQuery AJAX 方法,可以很方便的從後台獲取數據。
在前端獲取評論數據,只需用$.get(URL,callback)
方法即可方便的獲取,但其他細節仍使得處理過程比較繁瑣。
首先要添加一個窗口滾動的監聽器,當頁面滾動到底部時調用loadCommentWhenScollToBottom
函數載入評論。先判斷是否正在載入,防止重複載入,第一次載入要添加判斷標識。載入時還得獲取下一頁評論的url,然後調用$.get()
函數獲取評論數據,該函數是非同步請求,在得到伺服器響應後才能操作相應DOM。
$(function () { var bodyHeight = $("body").height(); var windowHeight = $(window).height(); if ((bodyHeight - windowHeight) < 100) { //頁面高度比瀏覽器高度小100時載入一次評論 loadCommentWhenScollToBottom(); } $(window).scroll(loadCommentWhenScollToBottom);});//滾動到頁面底部時載入評論function loadCommentWhenScollToBottom() { var docHeight = $(document).height(); var scrollBottom = $(window).scrollTop() + $(window).height(); if (docHeight - scrollBottom < 100) { if ($("#comment .loading").length == 0) { //防止重複載入 $("#comment").append(<div class="loading" stylex="text-align:center;">loading</div>); var last_ul = $("#comment>ul").last(); if (last_ul.length == 0) { getCommentList(); } else if (last_ul.attr("data-next") == "True") { var page = parseInt(last_ul.attr("data-page")); getCommentList(page + 1); } else { //評論載入完畢,不再發送請求 $(window).unbind("scroll"); $("#comment .loading").remove() } } }}//獲取評論列表function getCommentList(page) { var url = $("#comment").attr("data-url"); if (page) { url += "?page=" + page; } $.get(url, function (data, status) { //$.get()是非同步請求,在得到伺服器響應後才能操作相應DOM if (status == "success") { $("#comment").append(data); var reply_this = $(".reply-this"); reply_this.unbind("click"); //綁定reply方法 reply_this.click(reply); $("#comment .loading").remove(); } else { $("#comment .loading").html("無法載入評論"); } });}
7、動態添加二級評論表單
評論首頁的表單用於創建一級評論,但是二級評論的表單還需要動態創建。所以在載入完數據後,還要為回復按鈕綁定點擊事件用於創建二級評論表單。實現過程如下,原理簡單,不過比較繁瑣。同樣的,一級評論的表單也可以通過類似的方式動態創建,用哪種方式視情況而定。
//創建回復對話框function reply() { var reply_id = $(this).attr("data-reply-id"); var reply_user = $(this).siblings(".username").first().text(); var reply_list, comment_id, reply_form; //判斷回復的是幾級評論,並獲取相應的id if (reply_id) { reply_list = $(this).parent().parent(); comment_id = reply_list.siblings(".reply-this").attr("data-comment-id"); } else { reply_list = $(this).siblings(".reply-list"); comment_id = $(this).attr("data-comment-id"); } if ($("#comment-form").length == 0) { //沒有#comment-form意味著未登錄 $("body").animate({scrollTop: $("#comment .login").offset().top-100}, 500); } else { if (reply_list.siblings(".reply-form").length == 0) { //創建二級評論表單,該表單插在一級評論下方 reply_list.after(<form class="reply-form" action="/article/comment/reply/create/" method="post"> + <input type="hidden" name="reply" value> + <input type="hidden" name="comment" value></form>); reply_form = reply_list.siblings(".reply-form"); reply_form.append($("#comment-form").html()); reply_form.find("input[name=comment]").val(comment_id); reply_form.find(".submit").prepend(<span></span><span class="cancel">取消</span>); reply_form.find(".cancel").click(cancelReply); } else { //獲取已存在的表單 reply_form = reply_list.siblings(".reply-form"); } reply_form.find("input[name=reply]").val(reply_id); reply_form.find(".submit span").first().html(回復 + reply_user); $("body").animate({ scrollTop: reply_form.offset().top - 100 }, 500); }}function cancelReply() { $(this).parent().parent().remove();}
8、創建評論視圖
評論表單提交後需要保存到資料庫中,該過程可以利用django內建的CreateView簡單實現。原本的CreateView處理get請求時要返回含有表單的頁面,但我們已經通過別的方式將表單添加到頁面中了,EditArticleCommentMixin
的作用之一就是屏蔽get方法。另外還要覆蓋form_valid
方法,在保存評論之前將登錄用戶添加給評論對象。最後則是get_success_url
,評論創建成功後要轉向原來的頁面。由於這幾個方法對於一級和二級評論都適用,所以寫成Mixin更加簡潔。
from django.views.generic.edit import BaseCreateViewfrom django.contrib.auth.mixins import LoginRequiredMixinfrom django.urls import reverse, NoReverseMatchfrom django.core.exceptions import PermissionDenied, ImproperlyConfiguredclass EditArticleCommentMixin(): 修改文章評論Mixin def render_to_response(self, context, **response_kwargs): 禁止get方法和form無效的post raise PermissionDenied def form_valid(self, form): 保存前設置創建評論的用戶 self.object = form.save(commit=False) self.object.user = self.request.user self.object.save() return super().form_valid(form) def get_success_url(self): 操作成功後轉向文章詳情頁 try:#POST字典中必須提供文章的id url = reverse(blog:detail, kwargs={pk: self.request.POST[article]}) except NoReverseMatch: raise ImproperlyConfigured(Wrong URL to redirect.) return urlclass CreateArticleCommentView(LoginRequiredMixin, EditArticleCommentMixin, BaseCreateView): 創建一條新的文章評論 model = ArticleComment form_class = ArticleCommentFormclass CreateArticleCommentReplyView(CreateArticleCommentView): 創建一條新的文章二級評論 model = ArticleCommentReply form_class = ArticleCommentReplyForm
多級評論功能基本都完成了,如果想增加刪除功能也基本與之大同小異。雖然評論功能看似很簡單,但是實現起來卻可能涉及到很多內容,而且一些細節上的處理更是使得代碼變得臃腫。
雖然已經實現了評論功能,但前後端沒有完全分離,django模板雖然好用,但是當前端代碼承擔了大部分工作時,還是容易出錯。後端只負責提供數據,數據的渲染完全交給前端更好。由於不是很收悉前端開發,所以這裡我還是使用了模板系統。之後我打算再花時間修改一下代碼,實現後端發送json數據,前端渲染數據。
推薦閱讀:
※為什麼感覺django很難呢?
※知乎後台為什麼用python?
※可以多個server進程同時監聽一個unix socket文件么?
※Django 1.6 下模板怎麼用?