小程序实现分页 && 重复加载的问题(锁 && 避免死锁)

场景

  • 小程序分页
  • 分页的时候,如果用户在服务端返回数据之前,快速的多次触底(触发下一页请求的问题)

分析

  • 小程序实现分页的方式分为两种
    • 一种是使用scroll-view, 通过bindscrolltolower属性绑定处理;但是在纵向滚动的时候需要设置height, 这极可能导致图片被截断展示
    • 另外一种是Page 的onReachBottom(触底)生成周期, 捕捉到事件,
      • 组件中是没有这个生命周期的,但是可以在Page捕捉, 然后通过(不断变动的)属性和子组件通信, 子组件通过监控这个属性的变化(observer) 来判断加载下一页的时机
  • 在触发下一页的时候 (重复加载数据的问题)
    • 问题 如果在服务器还没有返回数据, 用户又再触底(上滑 然后下滑) 则会导致数据重复加载
    • 解决 加锁, 如果上次请求没有返回 则不可以再次请求

解决

  • 分页 将得到下一页的数据合并到原有的数据之上
  • 需要避免死锁, 需要捕捉服务器返回异常的时候,将锁解开
// 获取下一页的数据
    _onNext(new_value, old_value) {
      // 是否满足请求下一条的条件
      if (!this._canGetNext()) {
        return;
      }

      //  加锁
      this.setData({lock: true});

      // 请求
      book_model.getSearchResult(this.data.input, this.data.page + 1).then(response => {
        console.log(response, '搜索下一页书籍', new_value, old_value);
        // 将返回的新数据合并到就数据的尾部
        let list_search_result = this.data.list_search_result.concat(response.books);

        // 添加搜索关键字
        this.setData({
          list_search_result,
          total: response.total,
          page: response.page,
          page_size: response.page_size,
          lock: false
        });
      }).catch(response=>{
        // 解锁
        this.setData({
          lock : false
        }); 
      });

完整代码

import KeywordModel from '../../models/keyword.js';
import BookModel from '../../models/book.js';

let keyword_model = new KeywordModel(),
  book_model = new BookModel();

Component({
  /**
   * 组件的属性列表
   */
  properties: {
    unique_flag: {
      type: String,
      observer: '_onNext'
    }
  },

  /**
   * 组件的初始数据
   */
  data: {
    list_history: [], // 搜索记录
    list_hots: [], // 热门搜索列表
    list_search_result: [], // 搜索结果
    searching: 1, // 1未搜索 2搜索中 3 搜索结束
    input: '', // 输入的数据
    page: 1, // 当前页
    page_size: 10, // 每页的数量
    total: '', // 总数量
    lock: false, // 加载下一页的数据的锁,防止数据被重复加载(数据还没有返回就再次请求了下一次))
  },

  attached: function() {

    // 初始化环境
    this.initEnv();
  },

  /**
   * 组件的方法列表
   */
  methods: {
    // 获取下一页的数据
    _onNext(new_value, old_value) {
      // 是否满足请求下一条的条件
      if (!this._canGetNext()) {
        return;
      }

      //  加锁
      this.setData({lock: true});

      // 请求
      book_model.getSearchResult(this.data.input, this.data.page + 1).then(response => {
        console.log(response, '搜索下一页书籍', new_value, old_value);
        // 将返回的新数据合并到就数据的尾部
        let list_search_result = this.data.list_search_result.concat(response.books);

        // 添加搜索关键字
        this.setData({
          list_search_result,
          total: response.total,
          page: response.page,
          page_size: response.page_size,
          lock: false
        });
      }).catch(response=>{
        // 解锁
        this.setData({
          lock : false
        }); 
      });
    },

    // 是否满足请求下一页的条件
    _canGetNext() {
      // 如果没有了下一页 则不在进行服务器请求数据的操作
      if (this.data.total - this.data.page * this.data.page_size <= 0) {
        return false;
      }

      // 如果没有关键字 则是不进行请求的
      if (!this.data.input) {
        return false;
      }

      // 如果请求处于死锁的状态 则不可以发送请求
      if (this.data.lock) {
        return false;
      }
      return true;
    },

    // 清除输入的内容
    onClear(event) {
      // 如果本来就是空字符串  则不需要进行操作
      if (!this.data.input) {
        return;
      }

      this.setData({
        input: '',
        searching: 1
      });
      this._initHistory();
    },

    // 初始化环境
    initEnv() {
      // 初始化历史记录列表
      this._initHistory();

      // 初始化热门搜索列表
      this._initHot();
    },

    // 初始化历史记录列表
    _initHistory() {
      let list_history = keyword_model.getHistory();
      this.setData({
        list_history
      });
    },

    // 初始化热门搜索列表
    _initHot() {
      keyword_model.getHot().then(response => {
        this.setData({
          list_hots: response.hot ? response.hot : []
        });
      });
    },

    // 触发取消动作
    onCannel(event) {
      this.triggerEvent('cannel', {});
    },
    // 搜索
    // onSearch(event){
    //   // 获取搜索结果
    //   this.onTouch(event);
    // },
    // 搜索结果
    onTouch(event) {
      console.log(event, '标签触摸事件');
      let keyword = event.detail.content || event.detail.value;
      if (!keyword) {
        return;
      }

      // 搜索中
      this.setData({searching: 2});

      book_model.getSearchResult(keyword).then(response => {
        console.log(response, '搜索书籍');

        // 添加搜索关键字
        keyword_model.addToHistory(keyword);
        this.setData({
          list_search_result: response.books ? response.books : [],
          searching: 3,
          input: keyword,
          total: response.total,
          page: response.page,
          page_size: response.page_size
        });
      });
    },
  }
})

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值