文章收藏功能
需求分析:
- 进入到文章详情页之后,如果用户已收藏该文章,则显示已收藏,点击则为取消收藏,反之点击收藏该文章
- 因为只更新界面上部分元素,所以收藏和取消收藏的逻辑
代码实现
代码实现分为以下几步:
- 前端根据后台返回数据显示收藏或者取消收藏按钮
- 后端提供收藏与取消收藏接口
- 前端发起收藏或者取消收藏请求
对于收藏与评论的内容,建议使用 CSR 进行渲染
前端收藏界面展示
HTML 渲染
前端 HTML 收藏按钮展示
html
<!--收藏/取消收藏-->
<a href="javascript:;" class="collection block-center">收藏</a>
<a href="javascript:;" class="collected block-center" style="display: none">
<!-- <a href="javascript:;" class="collected block-center">-->
<span class="out">已收藏</span>
<span class="over" style="display: none">取消收藏</span>
</a>
收藏数据加载
前端 JavaScript 获取用户关注信息。
在获取用户是否收藏文章之前,需要判断用户是否登录,登录状态下,才请求后端接口获取用户是否收藏的数据,使用 ajax 进行动态更新。
用户判断用户是否登录的函数
javascriptfunction isLogin() { let access_token = localStorage.getItem("access_token"); return !access_token; }
请求后端,获取用户是否登录
javascript// filename: static/js/article.js let url = location.pathname.split("/"); const article_id = url[url.length - 1]; if (isLogin()) { // 加载当前用户是否收藏文章数据 $.ajax({ url: `/api/v1/article_collect?article_id=${article_id}`, type: "get", success: function (res) { if (res.is_collected) { $(".collection").hide(); $(".collected").show(); } else { $(".collection").show(); $(".collected").hide(); } }, }); }
后端返回收藏数据
python# filename: apis/index.py @index_api.get('/article_collect') @jwt_required() def article_collect_api(): article_id = request.args.get('article_id', type=int) article = ArticleORM.query.get(article_id) is_collected = False if article in current_user.collection_articles: is_collected = True return {"code": 0, "msg": "获取数据成功", "is_collected": is_collected}
前端优化收藏按钮显示
javascript// filename: static/js/article.js // 收藏按钮切换 $(".collected,.focused").on({ mouseover: function () { $(this).find(".out").hide().siblings(".over").show(); }, mouseout: function () { $(this).find(".over").hide().siblings(".out").show(); }, });
收藏逻辑实现
因为收藏与取消收藏,都需要请求后端登录的接口,所以需要添加下面的代码
javascript
$.ajaxSetup({
beforeSend: function (xhr) {
xhr.setRequestHeader("Authorization", localStorage.getItem("access_token"));
},
});
这段代码会给所有的 ajax 加上一个请求头信息
前端接口请求
javascript
// 点击收藏按钮
$(".collection").click(async function () {
const params = {
// 提取操作(收藏/取消收藏)
article_id: article_id,
};
// 没有登录,提交结束
if (!!isLogin()) {
layer.msg("请先登录");
return;
}
// 请求后端,进行收藏
$.ajax({
url: `/api/v1/article_collect`,
type: "post",
contentType: "application/json",
data: JSON.stringify(params),
success: function (res) {
if (res.code === 0) {
// 收藏成功
$(".collection").hide();
$(".collected").show();
layer.msg(res.msg, { icon: 1 });
} else {
layer.msg(res.msg);
}
},
});
});
后端接口响应
python
@index_api.post('/article_collect')
@jwt_required()
def article_collect_api_post():
req_data = request.get_json()
article_id = req_data.get('article_id')
article = ArticleORM.query.get(article_id)
current_user.collection_articles.append(article)
db.session.commit()
return {"code": 0, "msg": "收藏文章成功"}
取消收藏逻辑
前端接口请求
JavaScript
// 点击取消收藏按钮
$('.collected').click(async function () {
const params = {
// 提取操作(收藏/取消收藏)
article_id: article_id,
};
// 没有登录,提交结束
if (!!isLogin()) {
layer.msg('请先登录')
return
}
// 请求后端,进行收藏
$.ajax({
url: `/api/v1/article_collect`,
type: 'delete',
contentType: "application/json",
data: JSON.stringify(params),
success: function (res) {
if (res.code === 0) {
// 收藏成功
$('.collection').show();
$('.collected').hide();
layer.msg(res.msg, {icon: 1})
} else {
layer.msg(res.msg)
}
}
})
});
后端接口逻辑
python
@index_api.delete('/article_collect')
@jwt_required()
def article_collect_api_del():
req_data = request.get_json()
article_id = req_data.get('article_id')
article = ArticleORM.query.get(article_id)
current_user.collection_articles.remove(article)
db.session.commit()
return {"code": 0, "msg": "取消收藏文章成功"}