小程序列表经常遇到需要局部刷新的需求,具体场景如下:

  • 列表单项带有操作按钮,操作后需刷新列表数据,且列表保持不滚动,仅需更新当前项的数据,分页需要保持

  • 从列表单项进入详情页面,在详情页面进行操作后,再次返回列表时,列表数据需要更新,且列表保持不滚动,仅需更新当前项的数据,分页需要保持

问题思考和方案:

  • 针对第一条,相对来说比较好处理,只要在单项操作后,接口返回更新后的数据,我们在现有列表中找出操作项数据,进行数据替换即可;这里需要注意,除了替换,还有可能是移除(状态变了,不在当前列表了或者真实删除了),需要同步移除本地列表对应的数据项;

  • 第二条比较麻烦,在详情页操作了,返回列表时需要更新或者删除列表中具体一项,首先想到的就是通过 EventChannel 在列表页和详情页建立通讯,表面看起来好像确实能解决,但仔细推敲,其实是行不通滴;假如操作是在详情页之后的页面中进行,返回详情页需要更新,再返回列表页还需要更新,这里链路一长,就不靠谱了,很多列表都有类似的需求,太麻烦;

具体解决方案:

  • 针对第一条,列表单项更新或者删除,以下为示例代码:
Page({
  data: {
    listData: [],
  },
  // 更新列表项
  updataListItem(item, del = false) {
    // 通过单项id, 找到该项在列表数组中的下标
    const index = this.data.listData.findIndex(v => v.id === item.id);
    if (index > -1) {
      const updataKey = `listData[${index}]`;
      // 不要通过filter过滤出新的列表,再更新整个列表,效率低,不推荐;应该只更新对应单项
      this.setData({
        optionItem: item,
        [updataKey]: del ? null : item
      });
    } else {
      // console.log("更新列表时,未找到对应项")
    }
  }
})
  • 第二条我们的策略是在离开列表页面时,保持当前操作项的数据,在页面再次 show 时通过当前操作项查询最新的数据,并替换列表项;实现代码如下:
Page({
  data: {
    listData: [],
    optionItem: {}
  },
  // 页面显示时
  async onShow() {
    // 操作项数据不为空时,查询当前项的最新数据
    if (JSON.stringify(this.data.optionItem) !== "{}") {
      await this.queryItemDataAndUpdataList(this.data.optionItem);
    }
  },
  // 查看详情页面
  handleGoDetails(event) {
    const optionItem = event.currentTarget.dataset.item;
    this.setData({
      optionItem
    });
    wx.navigateTo({
      url: `/pages/details/details?id=${optionItem.id}`,
    });
  },
  // 通过id和列表查询条件获取最新数据,并更新列表数据
  async queryItemDataAndUpdataList(item) {
    // 省略实现代码 ... 
    this.updataListItem(itemData); // this.updataListItem(itemData, true); 
  },
  // 更新列表项
  updataListItem(item, del = false) {
    // 通过单项id, 找到该项在列表数组中的下标
    const index = this.data.listData.findIndex(v => v.id === item.id);
    if (index > -1) {
      const updataKey = `listData[${index}]`;
      // 不要通过filter过滤出新的列表,再更新整个列表,效率低,不推荐;应该只更新对应单项
      this.setData({
        optionItem: item,
        [updataKey]: del ? null : item
      });
    } else {
      // console.log("更新列表时,未找到对应项")
    }
  }
})

注意事项:

  • 分页不能通过 page 和 size 这种简单实现,需要更改为通过最后一条查询指定条数的方式实现;
  • 列表存在不必要获取数据的问题(列表进入详情,详情页面无任何操作,再次返回,其实无需再次获取当前操作项的数据),但无伤大雅;