Skip to content

文章收藏功能

需求分析:

  • 进入到文章详情页之后,如果用户已收藏该文章,则显示已收藏,点击则为取消收藏,反之点击收藏该文章
  • 因为只更新界面上部分元素,所以收藏和取消收藏的逻辑

代码实现

代码实现分为以下几步:

  • 前端根据后台返回数据显示收藏或者取消收藏按钮
  • 后端提供收藏与取消收藏接口
  • 前端发起收藏或者取消收藏请求

对于收藏与评论的内容,建议使用 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 进行动态更新。

  1. 用户判断用户是否登录的函数

    javascript
    function isLogin() {
      let access_token = localStorage.getItem("access_token");
      return !access_token;
    }
  2. 请求后端,获取用户是否登录

    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();
          }
        },
      });
    }
  3. 后端返回收藏数据

    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}
  4. 前端优化收藏按钮显示

    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": "取消收藏文章成功"}