成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久

您的位置:首頁技術文章
文章詳情頁

使用Vue+Django+Ant Design做一個留言評論模塊的示例代碼

瀏覽:81日期:2023-01-17 08:17:55

1.總覽

留言的展示參考網絡上參見的格式,如掘金社區:

使用Vue+Django+Ant Design做一個留言評論模塊的示例代碼

一共分為兩層,子孫留言都在第二層中

最終效果如下:

使用Vue+Django+Ant Design做一個留言評論模塊的示例代碼

使用Vue+Django+Ant Design做一個留言評論模塊的示例代碼

接下是數據庫的表結構,如下所示:

使用Vue+Django+Ant Design做一個留言評論模塊的示例代碼

有一張user表和留言表,關系為一對多,留言表有父留言字段的id,和自身有一個一對多的關系,建表語句如下:

CREATE TABLE `message` ( `id` int NOT NULL AUTO_INCREMENT, `date` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `content` text NOT NULL, `parent_msg_id` int DEFAULT NULL, `user_id` int NOT NULL, PRIMARY KEY (`id`), KEY `user_id` (`user_id`), KEY `message_ibfk_1` (`parent_msg_id`), CONSTRAINT `message_ibfk_1` FOREIGN KEY (`parent_msg_id`) REFERENCES `message` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT `message_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`) ON DELETE CASCADE ON UPDATE CASCADE) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8CREATE TABLE `user` ( `id` int NOT NULL AUTO_INCREMENT, `username` varchar(255) NOT NULL, `password` varchar(255) NOT NULL, `identity` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `username` (`username`)) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8

2.后臺接口

2.1獲取留言接口

在Django的views.py中定義兩個接口,一個負責提供留言內容,一個負責插入留言,如下:

# 獲取留言信息@require_http_methods([’GET’])def findAllMsg(request): response = {} try: sql = ’’’ SELECT msg1.*, user.username, msg2.username AS parent_msg_username FROM message msg1 LEFT JOIN (SELECT m.id, user.username FROM message m LEFT JOIN USER ON m.user_id = user.id )AS msg2 ON msg1.parent_msg_id = msg2.id LEFT JOIN USER ON msg1.user_id = user.id ORDER BY msg1.date DESC; ’’’ with connection.cursor() as cursor: cursor.execute(sql) response[’messages’] = sortMsg(cursor) response[’status_code’] = 200 except Exception as e: response[’status_code’] = 500 response[’error’] = e return JsonResponse(response)

先來看看這個sql能查出些什么東西:

使用Vue+Django+Ant Design做一個留言評論模塊的示例代碼

上面接口中的sorMsg()函數用于整理留言信息,使子留言和父留言能對應起來,算法實現如下:

# 整理留言信息返回格式def sortMsg(cursor): list = [] allMsg = dictfetchall(cursor) for i in range(len(allMsg)): tmpParent = allMsg[i] tmpChild = [] # 如果沒有屬于根評論,則搜索該評論下的所有子評論 if tmpParent.get(’parent_msg_id’) == None: tmpChild = bfs(tmpParent, allMsg) # 如果是子評論則跳過,子評論最終會出現在根評論的子節點中 else: continue tmpParent[’children’] = tmpChild # 格式化時間 tmpParent[’date’] = datetime.datetime.strftime(tmpParent[’date’], ’%Y-%m-%d %H:%M:%S’) list.append(tmpParent) return list# 搜索一條留言的所有子留言,廣度優先import queuedef bfs(parent, allMsg): childrenList = [] q = queue.Queue() q.put(parent) while(not q.empty()): tmpChild = q.get() for i in range(len(allMsg)): if allMsg[i][’parent_msg_id’] is not None and allMsg[i][’parent_msg_id’] == tmpChild[’id’]:childrenList.append(allMsg[i])q.put(allMsg[i]) # 子留言列表按時間降序排序 childrenList = sorted(childrenList, key = lambda d: d[’date’], reverse = True) # 格式化日期格式 for item in childrenList: item[’date’] = datetime.datetime.strftime(item[’date’], ’%Y-%m-%d %H:%M:%S’) return childrenList

用postman測試接口,得到的json格式如下:

{ 'messages': [ { 'id': 12, 'date': '2020-05-31 12:19:43', 'content': '你好啊,太棒了', 'parent_msg_id': null, 'user_id': 5, 'username': 'wangwu', 'parent_msg_username': null, 'children': [] }, { 'id': 11, 'date': '2020-05-31 12:18:55', 'content': '的時刻層6666666632n2面的思考名稱看到什么材料是isdafjoisdjiojildsc', 'parent_msg_id': null, 'user_id': 3, 'username': 'zhangsan', 'parent_msg_username': null, 'children': [] }, { 'id': 5, 'date': '2020-05-29 19:09:33', 'content': '發的發射點發吖方吖是發是呵等方5愛的非4阿瑟東方 發', 'parent_msg_id': null, 'user_id': 4, 'username': 'lisi', 'parent_msg_username': null, 'children': [{ 'id': 13, 'date': '2020-05-31 12:20:12', 'content': '號好好好矮好矮好矮好好', 'parent_msg_id': 5, 'user_id': 6, 'username': 'zhaoliu', 'parent_msg_username': 'lisi'} ] }, { 'id': 1, 'date': '2020-05-29 19:06:21', 'content': 'fasfdsafas法阿薩德方吖65阿瑟東方5是的發', 'parent_msg_id': null, 'user_id': 1, 'username': 'student', 'parent_msg_username': null, 'children': [{ 'id': 7, 'date': '2020-05-29 19:29:29', 'content': 'hfhf2h22h222223232', 'parent_msg_id': 6, 'user_id': 1, 'username': 'student', 'parent_msg_username': 'zhaoliu'},{ 'id': 6, 'date': '2020-05-29 19:09:56', 'content': '而離開離開鄰居哦i據哦i報價哦v保健品45465', 'parent_msg_id': 4, 'user_id': 6, 'username': 'zhaoliu', 'parent_msg_username': 'mike'},{ 'id': 4, 'date': '2020-05-29 19:09:14', 'content': '發送端非場地薩擦手d5asd32 1dadsrndsac十多次ds出錯', 'parent_msg_id': 2, 'user_id': 8, 'username': 'mike', 'parent_msg_username': 'lisi'},{ 'id': 3, 'date': '2020-05-29 19:08:56', 'content': '奮發惡法撒打發士大夫士大夫是大 大師傅撒', 'parent_msg_id': 2, 'user_id': 2, 'username': 'teacher', 'parent_msg_username': 'lisi'},{ 'id': 2, 'date': '2020-05-29 19:08:41', 'content': 'fasdfasdf發生的法撒旦飛灑多發點房地產', 'parent_msg_id': 1, 'user_id': 4, 'username': 'lisi', 'parent_msg_username': 'student'} ] } ], 'status_code': 200}

這個就是前臺所要的內容了。

其實一開始我是很直觀地認為是用深度優先來取出層層嵌套的留言的,如下:

# 遞歸搜索一條留言的所有子留言,深度優先def dfs(parent, allMsg): childrenList = [] for i in range(len(allMsg)): if allMsg[i][’parent_msg_id’] is not None and allMsg[i][’parent_msg_id’] == parent[’id’]: allMsg[i][’children’] = dfs(allMsg[i], allMsg) childrenList.append(allMsg[i]) return childrenList

這樣取出的json格式是這樣的:

{ 'messages': [ { 'id': 5, 'date': '2020-05-29 19:09:33', 'content': '發的發射點發吖方吖是發是呵等方5愛的非4阿瑟東方 發', 'parent_msg_id': null, 'user_id': 4, 'username': 'lisi', 'children': [{ 'id': 8, 'date': '2020-05-29T17:23:37', 'content': '哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈呵呵呵呵呵呵', 'parent_msg_id': 5, 'user_id': 3, 'username': 'zhangsan', 'children': []} ] }, { 'id': 1, 'date': '2020-05-29 19:06:21', 'content': 'fasfdsafas法阿薩德方吖65阿瑟東方5是的發', 'parent_msg_id': null, 'user_id': 1, 'username': 'student', 'children': [{ 'id': 2, 'date': '2020-05-29T19:08:41', 'content': 'fasdfasdf發生的法撒旦飛灑多發點房地產', 'parent_msg_id': 1, 'user_id': 4, 'username': 'lisi', 'children': [ { 'id': 4, 'date': '2020-05-29T19:09:14', 'content': '發送端非場地薩擦手d5asd32 1dadsrndsac十多次ds出錯', 'parent_msg_id': 2, 'user_id': 8, 'username': 'mike', 'children': [{ 'id': 6, 'date': '2020-05-29T19:09:56', 'content': '而離開離開鄰居哦i據哦i報價哦v保健品45465', 'parent_msg_id': 4, 'user_id': 6, 'username': 'zhaoliu', 'children': [ { 'id': 7, 'date': '2020-05-29T19:29:29', 'content': 'hfhf2h22h222223232', 'parent_msg_id': 6, 'user_id': 1, 'username': 'student', 'children': [] } ]} ] }, { 'id': 3, 'date': '2020-05-29T19:08:56', 'content': '奮發惡法撒打發士大夫士大夫是大 大師傅撒', 'parent_msg_id': 2, 'user_id': 2, 'username': 'teacher', 'children': [] }, { 'id': 9, 'date': '2020-05-29T17:27:13', 'content': 'alalla啦啦啦啦啦啦來的隊列李大水泛濫的薩拉發 的 第三方哈l', 'parent_msg_id': 2, 'user_id': 7, 'username': 'joke', 'children': [] } ]} ] } ], 'status_code': 200}

但仔細一想,實際頁面展示的時候肯定不能這樣一層層無限地嵌套下去,否則留言多了頁面就裝不下了,于是還是改成了兩層留言的格式,第二層使用廣度優先搜索將樹轉為列表存儲。

2.2 新增留言接口

前臺提供留言內容、留言者id以及父留言的id(如果不是回復信息的話就是空)

import datetime@require_http_methods([’POST’])def insertMsg(request): response = {} try: request.POST = request.POST.copy() request.POST[’date’] = datetime.datetime.now() msg = Message() msg.date = request.POST.get(’date’) msg.content = request.POST.get(’content’) msg.parent_msg_id = request.POST.get(’parent_msg_id’) msg.user_id = request.POST.get(’user_id’) msg.save() response[’msg’] = ’success’ response[’status_code’] = 200 except Exception as e: response[’error’] = str(e) response[’status_code’] = 500 return JsonResponse(response)

3.前臺設計

有了后臺提供的數據,前臺展示就比較簡單了。

留言板塊的設計我使用了Ant Design的留言組件。

留言界面主要由兩個組件所構成——留言區組件以及評論表單的組件

3.1主視圖Messeage.vue

<template> <div> <comment-message @handleReply='handleReply' :commentList='comments'></comment-message> <comment-area @reload='reload' :parentMsgId='replyMsgId' :replyMsgUsername='replyMsgUsername'></comment-area> </div></template><script>import CommentMessage from 'components/common/comment/CommentMessage';import CommentArea from 'components/common/comment/CommentArea';import { findAllMsg } from 'network/ajax';export default { name: 'Message', components: { CommentMessage, CommentArea }, data() { return { comments: [], replyMsgId: '', replyMsgUsername: '' }; }, mounted() { findAllMsg() .then(res => { this.comments = res.data.messages; }) .catch(err => { console.log(err); this.$router.push('/500'); }); }, methods: { handleReply(data) { this.replyMsgId = data.msgId; this.replyMsgUsername = data.msgUsername; }, reload() { this.$emit('reload') } }};</script><style></style>

3.2 留言區域組件CommentMessage.vue:

<template> <div id='commentMsg'> <div v-if='isEmpty(commentList)' class='head-message'>暫無留言內容</div> <div v-else class='head-message'>留言內容</div> <comment @handleReply='handleReply' v-for='(item1, index) in commentList' :key='’parent-’ + index' :comment='item1' > <!-- 二層留言 --> <template #childComment v-if='!isEmpty(item1.children)'> <comment v-for='(item2, index) in item1.children' :key='’children-’ + index' :comment='item2' @handleReply='handleReply' ></comment> </template> </comment> </div></template><script>import Comment from './Comment';import Vue from 'vue';export default { name: 'CommentMessage', components: { Comment }, props: { commentList: { type: Array, default: [] } }, methods: { isEmpty(ls) { return ls.length === 0; }, handleReply(data) { this.$emit('handleReply', { msgId: data.msgId, msgUsername: data.msgUsername }); } }};</script><style scoped>.head-message { font-size: 20px; text-align: center;}</style>

3.3 留言區域由多個Comment留言組件所構成,留言組件定義如下

<template> <a-comment> <span slot='actions' key='comment-basic-reply-to' @click='handlReply(comment.id, comment.username)' > <a href='http://www.piao2010.com/bcjs/11442.html#my-textarea'>回復</a> </span> <a slot='author' style='font-size: 15px'>{{comment.username}}</a> <a v-if='comment.parent_msg_username' slot='author' >@{{comment.parent_msg_username}}</a> <a-avatar slot='avatar' :src='http://www.piao2010.com/bcjs/require(’assets/images/login_logo.png’)' alt /> <p slot='content'>{{comment.content}}</p> <a-tooltip slot='datetime'> <span>{{comment.date}}</span> </a-tooltip> <slot name='childComment'></slot> </a-comment></template><script>export default { name: 'Comment', props: { comment: '' }, methods: { handlReply(msgId, msgUsername) { this.$emit('handleReply', { msgId, msgUsername }); } }};</script><style scoped>.reply-to { padding-left: 5px; color: #409eff; font-weight: 500; font-size: 15px;}</style>

3.4 添加留言或回復的表單組件CommentArea.vue

<template> <div> <a-comment id='comment-area'> <a-avatar slot='avatar' :src='http://www.piao2010.com/bcjs/require(’assets/images/login_logo.png’)' alt='Han Solo' /> <div slot='content'> <a-form-item> <a-textarea :rows='4' v-model='content' /> </a-form-item> <a-form-item> <a-button html-type='submit' :loading='submitting' type='primary' @click='handleSubmit' >添加留言</a-button> </a-form-item> </div> </a-comment> </div></template><script>import {insertMsg} from ’network/ajax.js’export default { data() { return { content: '', submitting: false }; }, props: { parentMsgId: '', replyMsgUsername: '' }, watch: { replyMsgUsername() { document .querySelector('#my-textarea') .setAttribute('placeholder', '回復: ' + '@' + this.replyMsgUsername); } }, methods: { handleSubmit() { if (!this.content) { return; } this.submitting = true; insertMsg(this.content, this.parentMsgId, this.$store.state.userId).then(res => { this.submitting = false; this.content = ''; document .querySelector('#my-textarea') .setAttribute('placeholder', ’’); this.$emit(’reload’) }).catch(err => { console.log(err); this.$router.push(’/500’) }) }, handleChange(e) { this.value = e.target.value; } }};</script>

組裝完成后實現的功能有:

留言界面的展示

使用Vue+Django+Ant Design做一個留言評論模塊的示例代碼

點擊回復按鈕跳到留言表單(這里我直接用了a標簽來錨定位,試過用scrollToView來平滑滾動過去,但不知道為什么只有第一次點擊回復按鈕時才能平滑滾動到,之后再點擊他就不滾動了。。。),并把被回復者的用戶名顯示在placeholder中

使用Vue+Django+Ant Design做一個留言評論模塊的示例代碼

點擊添加留言按鈕,清空placeholder,并自動實現router-view的局部刷新(不是整頁刷新)顯示出新增的留言

局部刷新的實現就是通過代碼中的自定義事件 reload ,具體就是從表單組件開始發送 reload 事件,其父組件 Message.vue 收到后,再繼續發送 reload 事件給外層的視圖Home.vue,Home的再外層就是App.vue了,Home.vue的定義如下:

<template> <el-container class='main-el-container'> <!-- 側邊欄 --> <el-aside class='main-el-aside'> <side-bar></side-bar> </el-aside> <!-- 主體部分 --> <el-main> <el-main> <router-view @reload='reload' v-if='isRouterAlive'></router-view> </el-main> </el-main> </el-container></template><script>import SideBar from 'components/common/sidebar/SideBar';export default { name: 'Home', components: { SideBar }, data() { return { isRouterAlive: true }; }, props: { isReload: '' }, watch: { isReload() { this.reload(); } }, methods: { reload() { this.isRouterAlive = false; this.$nextTick(() => { this.isRouterAlive = true; }); } }};</script><style scoped>.main-el-container { height: 750px; border: 1px solid #eee;}.main-el-aside { background-color: rgb(238, 241, 246);}</style>

里面有一個reload方法,通過改變isRouterAlive來讓router-view先隱藏,再顯示,實現重新掛載。

到此這篇關于使用Vue+Django+Ant Design做一個留言評論模塊的示例代碼的文章就介紹到這了,更多相關Vue+Django+Ant Design留言評論內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: Vue
相關文章:
成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久
欧美亚洲动漫制服丝袜| 日韩免费在线观看| fc2成人免费人成在线观看播放| 成人av网站在线观看免费| 99av国产精品欲麻豆| 精品视频在线免费看| 国产精品视频一二三区| 天天影视色香欲综合网老头| 国产精品99久久久久久久女警| 欧美国产综合| 免费国产一区二区| 日韩免费观看2025年上映的电影| 久久精品国产亚洲aⅴ| 99久久国产综合精品色伊| 一区二区三区四区五区视频| 欧美日韩性生活| 蜜臀精品久久久久久蜜臀| 欧美日韩国产亚洲一区| 91久久精品国产91性色tv| 国产视频一区不卡| 奇米777欧美一区二区| 欧美日本免费| 欧美综合欧美视频| 亚洲欧洲日产国产综合网| 麻豆国产欧美一区二区三区| 久久福利毛片| 久久久精品国产免大香伊| 日韩高清不卡一区二区三区| 欧美日韩国产三区| 国产免费成人在线视频| 国产一区二区调教| 亚洲日本欧美| 精品免费日韩av| 日韩av一级电影| 色婷婷综合在线| 亚洲欧美电影院| 成人美女在线观看| 色婷婷亚洲综合| 青青草原综合久久大伊人精品| 欧美日韩情趣电影| 成人免费毛片app| 久久久精品欧美丰满| 欧美日韩高清在线一区| 国产精品久久久久久久浪潮网站| 国产在线精品视频| 日韩欧美一级二级| 95精品视频在线| 亚洲人成亚洲人成在线观看图片| 亚洲高清在线播放| 精品乱人伦一区二区三区| 99精品热视频| 日韩伦理av电影| 女人香蕉久久**毛片精品| 一区二区中文视频| 亚洲在线不卡| 日韩一区中文字幕| 亚洲综合电影一区二区三区| 美国十次综合导航| 日韩欧美视频一区| 91亚洲精品久久久蜜桃| 777午夜精品免费视频| 日韩av一区二| 91精品国产综合久久婷婷香蕉| 99久久婷婷国产| 亚洲免费在线电影| 香蕉国产精品偷在线观看不卡| 理论电影国产精品| 久久日一线二线三线suv| 国产一区二区三区在线观看免费视频| 欧美一区二区在线观看| 久99久精品视频免费观看| 国产精品igao视频网网址不卡日韩| 亚洲精品免费在线播放| 欧美激情第二页| 成人欧美一区二区三区小说| 色综合久久久久综合99| 成人教育av在线| 亚洲三级免费电影| 欧美午夜一区二区三区免费大片| 成人av电影在线观看| 亚洲精品高清在线| 91精品国产综合久久久久| 亚洲裸体视频| 国产一区二区导航在线播放| 亚洲欧洲日韩在线| 欧美人与禽zozo性伦| 老汉av免费一区二区三区| 欧美成人艳星乳罩| 一区二区三区视频在线播放| 欧美成人vps| 久久国产精品一区二区三区四区| 成人午夜精品在线| 亚洲国产中文字幕| 亚洲永久网站| 粉嫩aⅴ一区二区三区四区 | 国产日韩1区| 国产福利一区在线| 欧美v国产在线一区二区三区| 国精品一区二区| 樱花影视一区二区| 日韩欧美专区在线| 97精品久久久午夜一区二区三区 | 国精品**一区二区三区在线蜜桃| 欧美日韩国产系列| 激情欧美日韩一区| 亚洲国产另类av| 精品国产人成亚洲区| 欧美国产三区| 久久99国产精品麻豆| 国产欧美视频一区二区| 欧美日韩一区二区三区视频| 日韩视频免费| 9人人澡人人爽人人精品| 蜜桃视频第一区免费观看| 中文字幕一区在线观看| 欧美一级欧美一级在线播放| 麻豆久久精品| 国内精品福利| gogogo免费视频观看亚洲一| 激情六月婷婷久久| 亚洲国产成人高清精品| 国产欧美日韩精品一区| 欧美一级二级三级乱码| 日本道免费精品一区二区三区| 欧美成人嫩草网站| 国产精品456露脸| 图片区小说区区亚洲影院| 国产欧美综合在线观看第十页| 在线播放亚洲一区| 成人免费视频国产在线观看| 亚洲成av人影院| 欧美人妇做爰xxxⅹ性高电影| 99香蕉国产精品偷在线观看| 午夜精品视频在线观看一区二区| 国产精品一区二区视频| 麻豆国产精品一区二区三区| 亚洲国产另类av| 亚洲综合无码一区二区| 在线播放日韩导航| 美女视频一区免费观看| 欧美色老头old∨ideo| 老司机免费视频久久| 一区二区91| 国产在线欧美| 欧美jizzhd精品欧美喷水| 亚洲妇女屁股眼交7| 亚洲伦理在线精品| 国产精品国产自产拍在线| 欧美精品一区二区三区蜜桃| 日韩一区二区电影| 欧美日韩精品一区二区在线播放| 色视频一区二区| 美女被久久久| 性欧美长视频| 亚洲最黄网站| 亚洲激情亚洲| 亚洲三级观看| 亚洲高清资源| 极品中文字幕一区| 韩国自拍一区| 影音先锋久久| 亚洲黄色大片| 亚洲久久视频| 夜夜爽www精品| 亚洲激情在线| 在线视频一区观看| 一区二区三区四区五区精品视频 | 亚洲激情黄色| 亚洲第一精品影视| 亚洲精品裸体| 一本色道婷婷久久欧美| 国产精品三区www17con| 高清免费成人av| 国产综合色精品一区二区三区| 久久国产精品色| 国产一区二区毛片| 成人app软件下载大全免费| 97超碰欧美中文字幕| 欧美日韩精品免费观看视一区二区| 欧美日韩国产亚洲一区| 91丨porny丨在线| 国模精品一区二区三区| 极品日韩av| 国产嫩草一区二区三区在线观看| 久久精品一区二区国产| 色一情一伦一子一伦一区| 欧美性生活影院| 5566中文字幕一区二区电影| 国内一区二区在线| 成人在线综合网| 欧美a级片一区| 亚洲欧洲精品一区二区| 国产欧美日韩综合一区在线播放| 亚洲一区精彩视频| 91成人免费在线视频| 717成人午夜免费福利电影| 精品理论电影在线观看 | 精品亚洲免费视频| 风流少妇一区二区| 欧美精品aa|