Python 基础
Python Web
Python 数据科学
Appearance
需求分析
<!--评论栏--> <!--评论栏-未登陆显示登陆之后进行评论--> <div class="comment_form_logout">登录发表你的评论</div> <!--评论栏-登陆之后显示用户头像并进行评论--> <form class="layui-form comment_form" action=""> <div class="layui-form-item"> <label class="layui-form-label person_pic"> <img src="/static/images/cat.jpg" alt="用户图标" /> </label> <div class="layui-input-block"> <textarea placeholder="请输入内容" class="layui-textarea"></textarea> </div> </div> <div class="layui-form-item"> <div class="layui-input-block" style="float: right"> <button type="submit" class="layui-btn layui-btn-primary layui-btn-sm" lay-submit lay-filter="comment" > 评论 </button> </div> </div> </form>
用户未登录的状态下,显示 登录发表你的评论,如果已经登录了,则是显示用户的头像以及评论表单。
登录发表你的评论
可以像收藏一样,默认显示第一个,获取信息之后,判断是否显示第二个。其中会需要用到用户的一些信息,可以在登录的时候,返回用户数据,前端将其保存到 localStorage 中。
localStorage
登录成功,后端返回用户数据
@index_api.post("/login") def login_api(): data = request.get_json() captcha = data["captcha"] captcha_uuid = data["captcha_uuid"] mobile = data["mobile"] password = data["password"] redis_captcha = redis_store.get_captcha_code(captcha_uuid) if redis_captcha != captcha: return {"msg": "验证码错误", "code": -1} q = db.select(UserORM) q = q.where(UserORM.mobile == mobile) user = db.session.execute(q).scalar() if not user: return {"msg": "用户不存在", "code": -1} if not user.check_password(password): return {"msg": "密码错误", "code": -1} access_token = create_access_token(user) user_data = user.as_json() del user_data['password_hash'] response = make_response( { "code": 0, "msg": "登录用户成功", "access_token": "Bearer " + access_token, "user": user_data } ) # 在 cookie 中设置 token set_access_cookies(response, access_token) return response
前端记录用户数据
// 发送请求 $.ajax({ type: "POST", contentType: "application/json", url: "/api/v1/login", data: JSON.stringify(field), success: function (data) { // 处理后端的响应数据 if (!data.code) { layer.msg(data.msg, { icon: 1 }); localStorage.setItem("access_token", data.access_token); localStorage.setItem("user_data", JSON.stringify(data.user)); setTimeout(function () { location.reload(); }, 2000); } else { layer.msg(data.msg, { icon: 2 }); } }, });
加载用户数据。未登录则提示登录,登录成功则可以评论
if (isLogin()) { $(".comment_form_logout").hide(); $(".comment_form").show(); // 如果用户登录,尝试获取用户的自定义头像 let user_data = JSON.parse(localStorage.getItem("user_data")); if (user_data.avatar_url !== null) { $(".person_pic img").attr("href", user_data.avatar_url); } } $(".comment_form_logout").click(function () { layer.msg("登录之后发表评论", { icon: 1 }); });
// 评论表单 form.on("submit(comment)", function (data) { let field = data.field; field["article_id"] = article_id; console.log(field); $.ajax({ url: "/api/v1/comment", type: "post", contentType: "application/json", data: JSON.stringify(field), success: function (res) { console.log(res); }, }); return false; });
@index_api.post("/comment") @jwt_required() def create_comment(): data = request.get_json() article_id = data.get("article_id") content = data.get("content") comment: CommentORM = CommentORM() comment.content = content comment.article_id = article_id comment.user_id = current_user.id comment.save() return {"code": 0, "msg": "评论文章成功"}
请求当前文章的评论,当然也可以分页。
// 加载文章的评论 登录之后才能查看评论 if (isLogin()) { $.ajax({ url: `/api/v1/article/${article_id}/comment`, type: "get", success: function (res) { console.log(res); res.data.forEach((article) => { let article_html = ` <div class="comment"> <div class="person_pic"> <img src="${ article.avatar_url || "/static/images/worm.jpg" }" alt="用户图标"> </div> <div class="comment-content"> <div class="username">${article.nickname}</div> <div class="comment_text"> ${article.content} </div> <div class="comment_info" data-cid="${article.id}"> <div class="comment_time">${dayjs( article.create_at, ).format("YYYY-MM-DD HH:mm:ss")}</div> <a href="javascript:;" class="comment_up" style="float: right">赞</a> <a href="javascript:;" class="comment_reply">回复</a> </div> </div> </div> `; $(".comment_list").append(article_html); }); }, }); }
@index_api.get("/article/<int:article_id>/comment") @jwt_required() def comment_view(article_id): q = db.select(CommentORM) q = q.where(CommentORM.article_id == article_id) q = q.order_by(CommentORM.create_at.desc()) ret: [CommentORM] = db.session.execute(q).scalars() ret_list = [] for r in ret: r: CommentORM d = r.as_json() d['nickname'] = r.user.nickname d['avatar_url'] = r.user.avatar_url ret_list.append(d) return {"code": 0, "msg": "获取评论成功", "data": ret_list}
在渲染模板时,给回复评论表单添加自定义属性,以记录当前回复的是哪一个评论
// 渲染子评论表单 $(".comment_list").on("click", ".comment_reply", function () { let current_comment_id = $(this).parent(".comment_info").attr("data-cid"); if (current_comment_id !== replay_comment_id) { $(".reply_form").remove(); replay_comment_id = $(this).parent(".comment_info").attr("data-cid"); $(this).parents(".comment-content").append(` <form class="layui-form reply_form" action=""> <div class="layui-form-item"> <textarea name="content" placeholder="请输入内容" class="layui-textarea"></textarea> </div> <div class="layui-form-item"> <div class="layui-input-block" style="float: right"> <button type="submit" class="layui-btn layui-btn-primary layui-btn-sm" lay-submit lay-filter="sub-comment">评论 </button> </div> </div> </form> `); } else { replay_comment_id = null; $(".reply_form").remove(); } console.log(replay_comment_id); });
// 评论表单 form.on("submit(sub-comment)", function (data) { let field = data.field; field["article_id"] = article_id; field["parent_id"] = replay_comment_id; $.ajax({ url: "/api/v1/comment", type: "post", contentType: "application/json", data: JSON.stringify(field), success: function (res) { console.log(res); }, }); return false; });
@index_api.post("/comment") @jwt_required() def create_comment(): data = request.get_json() article_id = data.get("article_id") content = data.get("content") parent_id = data.get("parent_id") comment: CommentORM = CommentORM() comment.content = content comment.article_id = article_id comment.user_id = current_user.id if parent_id: comment.parent_id = parent_id comment.save() return {"code": 0, "msg": "评论文章成功"}
@index_api.get("/article/<int:article_id>/comment") @jwt_required() def comment_view(article_id): q = db.select(CommentORM) q = q.where(CommentORM.article_id == article_id) q = q.where(CommentORM.parent_id == None) q = q.order_by(CommentORM.create_at.desc()) ret: [CommentORM] = db.session.execute(q).scalars() ret_list = [] for comment in ret: comment: CommentORM d = comment.as_json() d['nickname'] = comment.user.nickname d['avatar_url'] = comment.user.avatar_url if comment.child: sub_ret_list = [] for sub_comment in comment.child: sub_d = sub_comment.as_json() sub_d['nickname'] = sub_comment.user.nickname sub_d['avatar_url'] = sub_comment.user.avatar_url sub_ret_list.append(sub_d) d['child'] = sub_ret_list ret_list.append(d) return {"code": 0, "msg": "获取评论成功", "data": ret_list}
function render_sub_comment(child) { let sub_comment_html = ""; child.forEach((article) => { sub_comment_html += `<div class="sub-comment"> <div class="sub-username">${article.nickname}</div> <div class="comment_text"> ${article.content} </div> <div class="comment_info" data-cid="${article.id}"> <div class="comment_time">${dayjs(article.create_at).format( "YYYY-MM-DD HH:mm:ss", )}</div> <a href="javascript:;" class="comment_up" style="float: right">赞</a> <a href="javascript:;" class="comment_reply">回复</a> </div> </div> `; }); return sub_comment_html; } // 加载文章的评论 登录之后才能查看评论 if (isLogin()) { $.ajax({ url: `/api/v1/article/${article_id}/comment`, type: "get", success: function (res) { console.log(res); res.data.forEach((article) => { let article_html = ` <div class="comment"> <div class="person_pic"> <img src="${ article.avatar_url || "/static/images/worm.jpg" }" alt="用户图标"> </div> <div class="comment-content"> <div class="username">${article.nickname}</div> <div class="comment_text"> ${article.content} </div> <div class="comment_info" data-cid="${ article.id }"> <div class="comment_time">${dayjs( article.create_at, ).format("YYYY-MM-DD HH:mm:ss")}</div> <a href="javascript:;" class="comment_up" style="float: right">赞</a> <a href="javascript:;" class="comment_reply">回复</a> </div> `; if (article.child !== undefined) { console.log(render_sub_comment(article.child)); article_html += render_sub_comment(article.child); } article_html += ` </div> </div> `; $(".comment_list").append(article_html); }); }, }); }
文章评论
需求分析
评论表单渲染
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
用户未登录的状态下,显示
登录发表你的评论
,如果已经登录了,则是显示用户的头像以及评论表单。可以像收藏一样,默认显示第一个,获取信息之后,判断是否显示第二个。其中会需要用到用户的一些信息,可以在登录的时候,返回用户数据,前端将其保存到
localStorage
中。登录记录用户数据
登录成功,后端返回用户数据
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
前端记录用户数据
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
渲染评论表单
加载用户数据。未登录则提示登录,登录成功则可以评论
2
3
4
5
6
7
8
9
10
11
12
13
14
前端-评论提交事件
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
后端-记录评论
2
3
4
5
6
7
8
9
10
11
12
13
14
15
加载评论数据
前端-发送请求
请求当前文章的评论,当然也可以分页。
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
后端-返回评论数据
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
二级评论
前端-渲染二级评论表单
在渲染模板时,给回复评论表单添加自定义属性,以记录当前回复的是哪一个评论
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
前端-二级评论表单提交事件
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
后端-新增二级评论
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
二级评论数据渲染
后端-返回二级评论数据
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
前端-渲染二级评论内容
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