亚洲精品久久久中文字幕-亚洲精品久久片久久-亚洲精品久久青草-亚洲精品久久婷婷爱久久婷婷-亚洲精品久久午夜香蕉

您的位置:首頁技術(shù)文章
文章詳情頁

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

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

1.總覽

留言的展示參考網(wǎng)絡(luò)上參見的格式,如掘金社區(qū):

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

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

最終效果如下:

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

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

接下是數(shù)據(jù)庫的表結(jié)構(gòu),如下所示:

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

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

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中定義兩個接口,一個負(fù)責(zé)提供留言內(nèi)容,一個負(fù)責(zé)插入留言,如下:

# 獲取留言信息@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()函數(shù)用于整理留言信息,使子留言和父留言能對應(yīng)起來,算法實(shí)現(xiàn)如下:

# 整理留言信息返回格式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) # 如果是子評論則跳過,子評論最終會出現(xiàn)在根評論的子節(jié)點(diǎn)中 else: continue tmpParent[’children’] = tmpChild # 格式化時間 tmpParent[’date’] = datetime.datetime.strftime(tmpParent[’date’], ’%Y-%m-%d %H:%M:%S’) list.append(tmpParent) return list# 搜索一條留言的所有子留言,廣度優(yōu)先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': '發(fā)的發(fā)射點(diǎn)發(fā)吖方吖是發(fā)是呵等方5愛的非4阿瑟東方 發(fā)', '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是的發(fā)', '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據(jù)哦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': '發(fā)送端非場地薩擦手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': '奮發(fā)惡法撒打發(fā)士大夫士大夫是大 大師傅撒', 'parent_msg_id': 2, 'user_id': 2, 'username': 'teacher', 'parent_msg_username': 'lisi'},{ 'id': 2, 'date': '2020-05-29 19:08:41', 'content': 'fasdfasdf發(fā)生的法撒旦飛灑多發(fā)點(diǎn)房地產(chǎn)', 'parent_msg_id': 1, 'user_id': 4, 'username': 'lisi', 'parent_msg_username': 'student'} ] } ], 'status_code': 200}

這個就是前臺所要的內(nèi)容了。

其實(shí)一開始我是很直觀地認(rèn)為是用深度優(yōu)先來取出層層嵌套的留言的,如下:

# 遞歸搜索一條留言的所有子留言,深度優(yōu)先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': '發(fā)的發(fā)射點(diǎn)發(fā)吖方吖是發(fā)是呵等方5愛的非4阿瑟東方 發(fā)', '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是的發(fā)', 'parent_msg_id': null, 'user_id': 1, 'username': 'student', 'children': [{ 'id': 2, 'date': '2020-05-29T19:08:41', 'content': 'fasdfasdf發(fā)生的法撒旦飛灑多發(fā)點(diǎn)房地產(chǎn)', 'parent_msg_id': 1, 'user_id': 4, 'username': 'lisi', 'children': [ { 'id': 4, 'date': '2020-05-29T19:09:14', 'content': '發(fā)送端非場地薩擦手d5asd32 1dadsrndsac十多次ds出錯', 'parent_msg_id': 2, 'user_id': 8, 'username': 'mike', 'children': [{ 'id': 6, 'date': '2020-05-29T19:09:56', 'content': '而離開離開鄰居哦i據(jù)哦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': '奮發(fā)惡法撒打發(fā)士大夫士大夫是大 大師傅撒', 'parent_msg_id': 2, 'user_id': 2, 'username': 'teacher', 'children': [] }, { 'id': 9, 'date': '2020-05-29T17:27:13', 'content': 'alalla啦啦啦啦啦啦來的隊(duì)列李大水泛濫的薩拉發(fā) 的 第三方哈l', 'parent_msg_id': 2, 'user_id': 7, 'username': 'joke', 'children': [] } ]} ] } ], 'status_code': 200}

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

2.2 新增留言接口

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

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.前臺設(shè)計(jì)

有了后臺提供的數(shù)據(jù),前臺展示就比較簡單了。

留言板塊的設(shè)計(jì)我使用了Ant Design的留言組件。

留言界面主要由兩個組件所構(gòu)成——留言區(qū)組件以及評論表單的組件

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 留言區(qū)域組件CommentMessage.vue:

<template> <div id='commentMsg'> <div v-if='isEmpty(commentList)' class='head-message'>暫無留言內(nèi)容</div> <div v-else class='head-message'>留言內(nèi)容</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 留言區(qū)域由多個Comment留言組件所構(gòu)成,留言組件定義如下

<template> <a-comment> <span slot='actions' key='comment-basic-reply-to' @click='handlReply(comment.id, comment.username)' > <a href='http://www.aoyou183.cn/bcjs/11442.html#my-textarea'>回復(fù)</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.aoyou183.cn/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 添加留言或回復(fù)的表單組件CommentArea.vue

<template> <div> <a-comment id='comment-area'> <a-avatar slot='avatar' :src='http://www.aoyou183.cn/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', '回復(fù): ' + '@' + 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>

組裝完成后實(shí)現(xiàn)的功能有:

留言界面的展示

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

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

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

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

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

<template> <el-container class='main-el-container'> <!-- 側(cè)邊欄 --> <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先隱藏,再顯示,實(shí)現(xiàn)重新掛載。

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

標(biāo)簽: Vue
相關(guān)文章:
主站蜘蛛池模板: 一色综合 | 香蕉在线视频网站 | 久久永久免费视频 | 亚洲 欧美 国产另类首页 | 一区二区三区四 | 加勒比一本一道在线 | 国产乱码一区二区三区四区 | 久99久爱精品免费观看视频 | japanhdfree日本护士乱 | 毛片视频免费网站 | 亚洲 欧美 中文 日韩专区 | 天天影院色 | 国产亚洲人成在线影院 | 免费观看激色视频网站(性色) | 亚洲最大的黄色网址 | 日本aa在线| 美女18一级毛片免费看 | 真实国产乱视频国语 | 国产11一12周岁女毛片 | 欧美专区在线 | 成人禁啪啪网站 | 国产一级特黄高清免费大片 | 看全大色黄大色黄大片一级爽 | 日本特级黄色 | 欧美不卡一区二区三区 | 国产高清a毛片在线看 | 揄拍成人国产精品视频 | 美国一级毛片免费视频观看 | 色天天综合网色鬼综合 | 你懂的在线网站 | 黄色大片久久 | 免费永久在线观看黄网 | 国产一级视频在线观看 | 视频一区二区在线播放 | 第一区免费在线观看 | 黄网站免费在线观看 | 搜索黄色录像 | 色综合小说久久综合图片 | 亚洲欧美一区二区三区二厂 | 特色一级片 | 在线看免费观看韩国特黄一级 |