web页面 之 评论盖楼

一、前言

  评论是人与人之间,在网络上交互的一个重中之重的窗口,这在前端当中也算是一个不可或缺的模块!

  我们浏览各种能吐槽,能刷人气的网站,在各种头条的下面,都有评论这一项!我们围观水军吐槽的时候会发现,他们的评论楼有的是特别有层次感,一眼忘穿秋水知道怎么个评论大法,而有的设计的是一楼一楼的盖起来,要评论别人也是盖一层!简直是没有耐心去观战!估计是他们的前端想草草了事,整了个这么友好性近乎为零的评论楼,看的时候作为看官的我,想咂电脑的心都有。所以今天我们就简单的聊聊层次分明的盖楼方法!

二、原理

#我们前提规定评论的内容都存在数据库里,字段与下面字典中的key一致!当我们从数据库中取出数据,然后实现评论楼!
#从数据库中以字典类型读取到数据,这些数据存放在一个列表里,对这个列表进行循环,先为每个字典加入一对键值对"'child':[]",判断每个字典中的父ID是否有值,
#没值证明是鼻祖,有值就找到对应的父ID,把自己加入到其孩子键为"child"所对应的列表里,依次类推对所有的数据进行一次整理!

#数据库获取到的数据
msg_list = [
    {'id':1,'content':'xxx','parent_id':None},
    {'id':2,'content':'xxx','parent_id':None},
    {'id':3,'content':'xxx','parent_id':None},
    {'id':4,'content':'xxx','parent_id':1},
    {'id':5,'content':'xxx','parent_id':4},
    {'id':6,'content':'xxx','parent_id':2},
    {'id':7,'content':'xxx','parent_id':5},
    {'id':8,'content':'xxx','parent_id':3},
]

"""
数据重新整合之后,按照我们的逻辑得到的数据
msg_list = [
		{
			'id':1,'content':'xxx',parent_id:None,child:[
				{'id':4,'content':'xxx',parent_id:1},
				{'id':5,'content':'xxx',parent_id:1,child:[
					{'id':7,'content':'xxx',parent_id:5},
				]}]
			},
			{'id':2,'content':'xxx',parent_id:None,child:[
				{'id':6,'content':'xxx',parent_id:2},
			]},
			{'id':3,'content':'xxx',parent_id:None,child:[
				{'id':8,'content':'xxx',parent_id:3},
			]},
	]
"""
"""
最终效果展示:
	评论1
		评论4
			评论6
		评论5
	评论2
	评论3
"""

针对这种显示方式,我们有两种方法:
	一种是在服务端这边,通过函数做好数据的整合然后处理成要显示的效果的HTML标签字符串,然后发送给客户端;
	另一种是把整合好的数据发送给客户端,让客户端去实现最终显示的效果!
由于有子父ID判断的问题,需要用到递归函数,递归函数的弊端就是执行慢,严重占用机器的性能!如果是多人次的访问就会给服务器带来很大的压力;
而把数据传递到客户哪里,让客户的页面通过JS实现最终显示,虽然是把递归放到了客户端上,但是从全局上讲客户端仅仅是处理这个递归函数,而服务端仅是一个数据整合的功能,会大大提交服务器的效率!
	
#按照这个重新整合出来的已经分好等级的数据,通过父ID和child进行整理拼接,在页面上实现有层级的评论楼!
#python里面的apend之类的东西都是引用的原来数据的内从地址,对原数据进行操作的话
#我们引用的数据也会发生一样的变化(字典列表之类的)
 
#浙江吴彦祖的方法:
# for i in msg_list:
#     i['child']=[]
# for i in range(len(msg_list)-1,-1,-1):
#     if msg_list[i]['parent_id']:
#         msg_list[msg_list[i]['parent_id'] - 1]['child'].append(msg_list[i])
# new_msg_list = [i for i in msg_list if i['parent_id'] is None]
# print(new_msg_list)
 
#老师讲的方法
# v=[row.setdefault('child',[]) for row in msg_list] #这和地下的第一个for循环的作用是一样的,给每一个元素加一个'child':[]
# print(msg_list)
#如果我们想加快索引(快点找到数据的话)就建一个字典的数据结构,这是因为字典中的key会以一种特殊方式存于内存之中,他这种结构就是为了方便查找对应的值!
msg_list_dict={} #加快索引,节省时间
for item in msg_list:
    item['child']=[]
    msg_list_dict[item['id']]=item #字典中key为item['id'],value为item
    #把字典数据结构填上数据,能够加快索引,而且我们数据还是占得原来的内从空间
    #我们只是引用了数据的内容空间,所以不存在新的数据结构浪费空间一说
result=[]
for item in msg_list:
    pid=item['parent_id']
    if pid: #如果parent_id不为空,说明它是子级,要把自己加入对应的父级
        msg_list_dict[pid]['child'].append(item)
    else: #如果为空,说明他是父级,鼻祖级别,要把它单独立出来用
        result.append(item)
#result就是我们最终要的结果,因为这里面全是引用,所有数据的内存地址都没有变
#只不过被多个数据结构引用了而已
print(result)

三、精简版本

Django app中---->views.py函数:

def comments(request,nid):
    """
        评论
    :param request:
    :param nid:
    :return:
    """
    ret = {"status":True,"data":None,"msg":None}#定义初始值
    try:
        msg_list = models.Comment.objects.values("nid","article_id","content","create_time","reply_id","user_id")
        msg_list_dict = {}  # 定义一个字典
        for item in msg_list:
            item["child"] = []  # 给列表中的每个字典添加一对键值对 "child"=[]
            msg_list_dict[item["nid"]] = item  # 把数据重组成一个新的字典,以id为key,原字典为values

        result = []  # 定义一个新列表
        for item in msg_list:
            pid = item["reply_id"]  # 父id
            if pid:  # 如果父id存在的话
                msg_list_dict[pid]["child"].append(item)  # 就从新字典中为id为父id的child添加值
            else:
                result.append(item)  # 否则的话,就把对应的字典添加到新列表中(列表信息重组,把重复的值去掉)。
        ret["data"] = result
    except Exception as e:
       ret["status"] = False
       ret["msg"] = str(e)
    return HttpResponse(json.dumps(ret))

Django 中模版 HTML代码:

//我就是尝试着加了个框,和能看到位置手写的值
<div class="comments">
        <div></div>
        <div class="coms_head">评论列表</div>
        <div class="coms_body">
            <div class="coms_items_title">#1楼</div>
            <div></div>
            <div class="coms_items_info">你猜我写的啥?</div>
            <div id="commentArea"></div>
        </div>
</div>

重点来啦!JS实现多级评论:

<script type="text/javascript" src="/static/js/jquery-3.2.1.js"></script>
<script>
    $(function(){
        $.ajax({
            url:"/comments-{{ articles.nid }}.html",
            type:"GET",   //以GET方式获取数据
            dataType:"JSON",
            success:function(arg){
                if(arg.status){
                    var comment = commentTree(arg.data);
                    $("#commentArea").append(comment);
                } else{
                    alert(arg.msg);
                }
            }
        })
    });
    //自定义字符串格式化的方法(有一张博客里写过!)
    String.prototype.Format = function(arg){
		var temp = this.replace(/\{(\w+)\}/g,function(k,kk){
			return arg[kk];
		});
		return temp;
	};
    //简单实现评论楼的功能,通过递归判断信息中有没有child项,以实现主评论和子评论之间有层次关系
	function commentTree(commentList){
		var comment_str = "<div class='comment' >";
		$.each(commentList,function(k,row){
			var temps = "<div class='content'>{content}</div>".Format({"content":row.content});
			comment_str += temps;
			if (row.child.length>0){
				comment_str +=commentTree(row.child);
			}
		});
		comment_str += "</div>";
		return comment_str;
	}
</script>

必不可少的路由:

url(r'^comments-(\w+).html$',views.comments),

 

posted @ 2017-08-13 19:08  细雨蓝枫  阅读(478)  评论(0编辑  收藏  举报