unicloud云开发进阶42-项目26前端实现无感渲染处理异常恶意点击

239 阅读2分钟

云对象 自动显示交互界面

文档:uniapp.dcloud.net.cn/uniCloud/cl…

背景:每次写客户端联网的代码时,开发者都免不了重复写一堆代码:先调用loading等待框,联网结束后再关闭loading,如果服务器异常则弹出提示。

从HBuilderX 3.4.6起,调用云对象的方法时,默认会自动显示交互/提示界面。

  1. 在请求联网开始时显示loading等待框,
  2. 结束后隐藏loading
  3. 如果请求报错,显示弹窗(也可配置为显示Toast)

如果默认显示的UI不符合你的需求,你可以通过配置自定义一些交互内容,也可以直接关闭自动显示的交互界面。

关闭自动显示UI

  // 引入自定义云对象 utilsObj
  const utilsObj = uniCloud.importObject("utilsObj",{
    customUI:true
  });

image.png

关闭之后,提示框被隐藏了 image.png

点赞数增加

之前的逻辑:点击之后发送网络请求,然后在数据库进行自增,然后页面中的点赞数自增,再把isLike状态进行改变,这种实现方法比较慢,会产生卡顿的感觉

之前是一类与后端处理,可以用前端来解决,该做的网络请求还是做,但是先把效果展现给用户,再做网络请求就没有延迟 同时通过判断用户是否点击来实现点赞数的自增或自减

// this.detailObj.isLike为真表示已经点过赞了,调用云对象方法使点赞数自增或自减
this.detailObj.isLike ? this.detailObj.like_count-- : this.detailObj.like_count++
// 点赞 通过取反实现 先改变前端状态,增加体验感
this.detailObj.isLike = !this.detailObj.isLike

没点赞时,只有灰色按钮的手

image.png

点赞后,按钮高亮,出现数字 image.png

如果用户恶意操作,一直来回点按钮,实际上每次都发送了网络请求,就会增加服务器的负担,同时,在网络请求慢的情况,还会出现负数或大数的情况 先用变量this.like保存时间,再赋值

      // 点击点赞按钮,在数据库中增加一条点赞记录
      // article_id=="${this.artId} 用户创文章ID等于数据库保存文章ID
      // user_id==$cloudEnv_uid 数据库的id 等于 客户端上传的id 云端变量
      async clickLike(){
        // 一秒之内不允许点击
        let time=Date.now();
        // 这里写的这个属性this.like是不存在的,会自动创建出来
        if(time -this.likeTime < 2000){
          uni.showToast({
            title:"操作太频繁,请稍后再试",
            icon:"none"
          })
          return;
        }
        
        // this.detailObj.isLike为真表示已经点过赞了,调用云对象方法使点赞数自增或自减
        this.detailObj.isLike ? this.detailObj.like_count-- : this.detailObj.like_count++
        // 点赞 通过取反实现 先改变前端状态,增加体验感
        this.detailObj.isLike = !this.detailObj.isLike
        // 保存用户点赞时间
        this.likeTime = time;

抽离出一个方法来

      // 点击点赞按钮,在数据库中增加一条点赞记录
      // article_id=="${this.artId} 用户创文章ID等于数据库保存文章ID
      // user_id==$cloudEnv_uid 数据库的id 等于 客户端上传的id 云端变量
      async clickLike(){
        // 一秒之内不允许点击
        let time=Date.now();
        // 这里写的这个属性this.like是不存在的,会自动创建出来
        if(time -this.likeTime < 2000){
          uni.showToast({
            title:"操作太频繁,请稍后再试",
            icon:"none"
          })
          return;
        }
        
        // this.detailObj.isLike为真表示已经点过赞了,调用云对象方法使点赞数自增或自减
        this.detailObj.isLike ? this.detailObj.like_count-- : this.detailObj.like_count++
        // 点赞 通过取反实现 先改变前端状态,增加体验感
        this.detailObj.isLike = !this.detailObj.isLike
        // 保存用户点赞时间
        this.likeTime = time;
        // 调用点赞操作数据库方法
        this.likeFun()
      },
      //点赞操作数据库的方法
      async likeFun(){
        let count = await db.collection("quanzi_like").where(`article_id=="${this.artId}" && user_id==$cloudEnv_uid`).count()
        // count中有一个值total
        // 数据库有点赞记录就是1,没有是0
        if(count.result.total){
          // 用户取消点赞则删除数据库的点赞记录
          db.collection("quanzi_like").where(`article_id=="${this.artId}" && user_id==$cloudEnv_uid`).remove();
          // 调用云对象的operation方法,将文章表的点赞数自减1
          utilsObj.operation("quanzi_article", "like_count", this.artId,-1)
        }else{
          // 向数据库新增点赞记录
          // 把当前文章ID保存到数据库的文章ID字段
          db.collection("quanzi_like").add({
            article_id:this.artId
          })
          // 调用云对象的operation方法,将文章表的点赞数自增1
          utilsObj.operation("quanzi_article", "like_count", this.artId,1)
          }
      },

获取到详情之后改变页面标题

          // 网络数据获取完成后将骨架屏状态重置为false
          this.loadState = false;
          // 是否点过赞
          let isLike = res.result.data._id.quanzi_like.length ? true : false;
          // 向返回值赋值 把是否点过赞赋给返回值
          res.result.data.isLike = isLike;
          // 把获取到的用户信息赋值
          this.detailObj = res.result.data
          uni.setNavigationBarTitle({
            // 将当前文章标题作为页面title
            title:this.detailObj.title
          })
        }).catch(err=>{
          this.errFun();

完整的方法:

      // 获取网络数据
      getData(){
        // 将主表副表都查出一个临时表来
        let artTemp = db.collection("quanzi_article").where(`_id=="${this.artId}"`).getTemp();
        let userTemp =  db.collection("uni-id-users").field("_id,username,nickname,avatar_file").getTemp();
        let likeTemp = db.collection("quanzi_like").where(`article_id=="${this.artId}" && user_id==$cloudEnv_uid`).getTemp();
        // 两张副表单独与主表关联,副表之间没有关系
        db.collection(artTemp,userTemp,likeTemp).get(
        {
          getOne:true
        }).then(res=>{
          console.log(res);
          // 如果data参数不存在吗,表示传递的参数id有误
          if(!res.result.data){
            this.errFun();
            return;
          }
          // 网络数据获取完成后将骨架屏状态重置为false
          this.loadState = false;
          // 是否点过赞
          let isLike = res.result.data._id.quanzi_like.length ? true : false;
          // 向返回值赋值 把是否点过赞赋给返回值
          res.result.data.isLike = isLike;
          // 把获取到的用户信息赋值
          this.detailObj = res.result.data
          uni.setNavigationBarTitle({
            // 将当前文章标题作为页面title
            title:this.detailObj.title
          })
        }).catch(err=>{
          this.errFun();
        })
      }

image.png