日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

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

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

瀏覽:125日期: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://m.b3g6.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://m.b3g6.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://m.b3g6.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
相關文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
青青草精品视频| 成人日韩在线| 99国产精品视频免费观看一公开 | 男人天堂欧美日韩| 一区二区自拍| 欧美日韩国产欧| 中文精品视频| 热久久国产精品| 亚洲精品伊人| 国产精品色在线网站| 国产精品v日韩精品v欧美精品网站| 蜜臀va亚洲va欧美va天堂| 亚洲人成高清| 国产欧美日韩在线观看视频| 国产精成人品2018| 日韩不卡一区| 三级欧美韩日大片在线看| 欧美/亚洲一区| 99视频精品| 日本一区福利在线| 国产精品一区二区av交换 | 日韩高清在线观看一区二区| 欧美在线看片| 麻豆精品视频在线| 香蕉视频亚洲一级| 香蕉精品久久| 亚洲精品影视| 精品日韩一区| 欧美.日韩.国产.一区.二区| 少妇精品久久久一区二区三区| 国产精品xxx| 久久免费大视频| 日韩一区二区三免费高清在线观看 | 欧美丰满日韩| 黄色精品网站| 日韩国产一区二| 国产精品视频一区二区三区综合| 97在线精品| 男女精品网站| 精品91福利视频| 久热综合在线亚洲精品| 麻豆一区二区99久久久久| 久久美女精品| 国产精品一区亚洲| 国产99久久久国产精品成人免费| 最新亚洲国产| 成人在线丰满少妇av| 最新日韩欧美| 麻豆久久一区| 爽好久久久欧美精品| 精品在线网站观看| 91久久国产| 国产精品成人3p一区二区三区| 国产99精品一区| 国产精品xxx| 久久亚洲视频| 麻豆视频在线看| 亚洲人成毛片在线播放女女| 国产 日韩 欧美 综合 一区| 男女精品网站| 97精品在线| 欧美综合精品| 婷婷激情久久| 精品国产麻豆| 日本一不卡视频| 1024精品久久久久久久久| 国产亚洲欧美日韩精品一区二区三区 | 老司机久久99久久精品播放免费| 久久久国产精品网站| 国产精品女主播一区二区三区| 欧美激情麻豆| 日韩亚洲精品在线| 国产在线看片免费视频在线观看| 婷婷综合成人| 激情综合自拍| 国产精品精品| 久久精品99国产精品日本| 日韩视频二区| 日韩在线短视频| 久久不见久久见免费视频7| 免费人成黄页网站在线一区二区| 日韩欧美国产精品综合嫩v| 国产精品mm| 日韩高清在线不卡| 欧美专区18| 播放一区二区| 国产精品亚洲成在人线| 日韩精品一二区| 久久精品免费一区二区三区| 国产精品magnet| 日本a级不卡| 久久成人一区| 欧美午夜精彩| 免费一二一二在线视频| 国产成人调教视频在线观看| 奇米狠狠一区二区三区| 日韩中文字幕一区二区三区| 欧美日韩四区| 在线日韩av| 国产91精品对白在线播放| 日韩在线免费| 麻豆一区二区三| 国产日韩高清一区二区三区在线| 亚洲视频二区| 午夜一级在线看亚洲| 激情自拍一区| 影视先锋久久| 亚洲www啪成人一区二区| 日韩精品1区| 日韩欧美精品| 日韩毛片在线| 欧美成人基地| 欧美二三四区| 久久久夜夜夜| 亚洲国产一区二区在线观看 | 亚洲精一区二区三区| 蜜臀久久99精品久久久久宅男| 国产亚洲精品自拍| 亚洲免费黄色| 亚洲一区网站| 在线一区二区三区视频| 一区二区日韩免费看| 中文字幕免费精品| 日韩欧美在线精品| 欧美日韩亚洲国产精品| 国产丝袜一区| 麻豆国产欧美一区二区三区| 精品亚洲a∨一区二区三区18| 国产精品手机在线播放| 国产一区二区三区四区二区 | 悠悠资源网久久精品| 精品91久久久久| 久久亚洲欧洲| 日本视频一区二区| 国产精品第十页| 都市激情国产精品| 久久久影院免费| 首页国产欧美日韩丝袜| 日精品一区二区三区| 国产精品一级| 国产欧洲在线| 欧美日韩一区二区三区视频播放| 欧美理论视频| 国产精品日韩| 日韩av网站免费在线| 美女毛片一区二区三区四区最新中文字幕亚洲| 久久久免费人体| 久久三级视频| 综合亚洲色图| 老鸭窝一区二区久久精品| 92国产精品| 美女91精品| 国产精品视频一区二区三区四蜜臂| 欧美激情另类| 日韩激情av在线| 在线手机中文字幕| 亚洲少妇诱惑| 国产欧美自拍| 久久精品123| 爽好多水快深点欧美视频| 国产日韩三级| 成人精品亚洲| 亚洲精选久久| 98精品视频| 亚洲伊人影院| 精品伊人久久久| 欧美日韩精品免费观看视频完整| 日韩黄色av| xxxxx性欧美特大| 午夜在线精品| 久久99高清| 欧美va亚洲va日韩∨a综合色| 亚洲精品成a人ⅴ香蕉片| 精品亚洲二区| 免费成人在线观看| 97在线精品| 日韩一区免费| 蜜桃国内精品久久久久软件9| 日韩国产在线一| 欧美精品高清| 日韩av字幕| 国产一区二区中文| 国产精品15p| 天堂va蜜桃一区二区三区| 欧美日本不卡| 波多野结衣一区| 国产精品综合| 午夜av一区| 日韩av有码| 日韩三级精品| 久久久久久黄| 免费日韩成人| 一区二区精品| 99久久亚洲精品| 欧美1区二区| 日韩黄色av| 亚洲欧美视频| 欧洲av一区二区| 久久精品国产久精国产爱| 男女男精品视频网|