web页面 之 评论盖楼
一、前言
评论是人与人之间,在网络上交互的一个重中之重的窗口,这在前端当中也算是一个不可或缺的模块!
我们浏览各种能吐槽,能刷人气的网站,在各种头条的下面,都有评论这一项!我们围观水军吐槽的时候会发现,他们的评论楼有的是特别有层次感,一眼忘穿秋水知道怎么个评论大法,而有的设计的是一楼一楼的盖起来,要评论别人也是盖一层!简直是没有耐心去观战!估计是他们的前端想草草了事,整了个这么友好性近乎为零的评论楼,看的时候作为看官的我,想咂电脑的心都有。所以今天我们就简单的聊聊层次分明的盖楼方法!
二、原理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | #我们前提规定评论的内容都存在数据库里,字段与下面字典中的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函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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代码:
1 2 3 4 5 6 7 8 9 10 11 | //我就是尝试着加了个框,和能看到位置手写的值 < 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实现多级评论:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | <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> |
必不可少的路由:
1 | url(r '^comments-(\w+).html$' ,views.comments), |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· C# 深度学习:对抗生成网络(GAN)训练头像生成模型
· .NET 适配 HarmonyOS 进展
· 如何给本地部署的DeepSeek投喂数据,让他更懂你
· 超详细,DeepSeek 接入PyCharm实现AI编程!(支持本地部署DeepSeek及官方Dee
· 用 DeepSeek 给对象做个网站,她一定感动坏了
· .NET 8.0 + Linux 香橙派,实现高效的 IoT 数据采集与控制解决方案
· .NET中 泛型 + 依赖注入 的实现与应用