搜索
首页web前端uni-app聊聊uniapp的scroll-view下拉加载

聊聊uniapp的scroll-view下拉加载

最近在做一个微信小程序直播模块,模块里的聊天室功能是用scroll-view + 一维数组的形式展示的,而且也没有进行任何的优化,导致用户的体验感比较差

首先模拟一下优化前的聊天室情况

1.gif

肉眼可见的蛋疼~

但是优化还是得优化滴,不优化是不可能滴,但是在开始之前,我觉得有必要把优化步骤拆分为以下两点?

1. 不再使用scroll-into-view设置锚点

由于旧版本使用的是scroll-view + 一维数组的形式实现的,这就导致在数据添加后页面总会显示加载后的最后一条信息,而不是加载前的最后一条信息,因此上一任开发者使用了scroll-into-view属性作为数据加载后的回位锚点,但是由于锚点指向的切换和数据加载并不是同步发生的,这就导致出现回弹的现象

2. 大量数据的处理

因为是聊天室功能,因此不可避免的需要加载大量的用户对话、图片等内容,又因为scroll-view本身并不适合加载大量的数据(太菜了想不出来其他办法),故而需要在数据的加载和显示部分下点功夫处理一下

3. 附加功能处理

聊天室原本还有返回底部等功能存在,因此在完成优化后原本的功能也不能忽略

OK开工~

1、倒置scroll-view

为什么要倒置scroll-view呢?从上面的第一点我们可以看出,如果需要正序地插入数据,那么就会不可避免地出现数据加载后无法显示后面数据的情况,但是想要解决这种情况又需要使用scroll-into-view属性,那么如果需要彻底地解决这个问题,就需要从问题的根源scroll-view下手

首先是修改前的代码?

<view class="live-content">这是一个直播画面</view>
  <scroll-view
    class="scroll"
    :scroll-y="true"
    :scroll-into-view="scrollIntoView"
    @scrolltoupper="upper"
  >
    <view
      :id="item.index"
      :style="{
        backgroundColor: item.color,
        height: &#39;200rpx&#39;,
        lineHeight: &#39;200rpx&#39;,
        textAlign: &#39;center&#39;,
      }"
      v-for="item in scrollData"
      :key="item.index"
    >
      {{ item.data }}
    </view>
  </scroll-view>
const scrollIntoView = ref("index1");
const upper = () => {
  let lastNum = scrollData.value[0].data;
  let newArr = [];
  for (let index = 1; index <= 10; index++) {
    newArr.push({
      color: getRandomColor(),
      data: lastNum + index,
      index: `index${lastNum + index}`,
    });
  }
  scrollData.value.unshift(...newArr.reverse());
  // 这里可以使用nextTick来替换一下,结果也是一样的,但是为了更明显的回弹效果我使用了定时器
  setTimeout(() => {
    scrollIntoView.value = `index${lastNum}`;
    console.log("scrollIntoView  :>>", scrollIntoView.value);
  }, 100);
};
const getRandomColor = () => {
  return "#" + Math.random().toString(16).substr(2, 6);
};

那么就先来试一下倒置scroll-view到底也没有效果

首先我们需要给scroll-view套上一个transform:rotate(180deg)的属性,然后再给内部的子元素也套上同样的属性,别忘了给存放数据的数组也倒置一下,最重要的,把scroll-view上的scroll-into-view属性去掉,就会得到这样的效果?

2.gif

还有就是此时滚动条的位置是在左边的,如果有需要可以使用CSS属性去掉,或者自行模拟,下面是去去除滚动条的CSS样式?

::-webkit-scrollbar {
  display:none;
  width:0;
  height:0;
  color:transparent;
}

到这里还只是第一步,下一步是如何下拉加载数据

此时我们的scroll-view是处于倒置的状态,也就是说顶部是底,底部才是顶(搁着绕口令呢),所以之前使用的scrolltoupper触顶方法要替换成scrolltolower触底方法才能实现“下拉加载”

3.gif

下面是目前的聊天室看起来好多了

4.gif

2、大量数据的处理

我第一个想法就是非常经典的虚拟列表,但是此前所看的很多关于虚拟列表的文章都是在web端实现的,似乎小程序领域里并不是一个被经常采用的方法,但是所幸还是找到了如何在微信小程序实现虚拟列表的资料,详情可以查看这篇文章?微信小程序虚拟列表

OK说干就干,那么第一步就是要明确实现虚拟列表需要什么样的数据结构,虚拟列表其实简单地说就是当某一个模块的数据超出了可视范围就将其隐藏,那么如何将数据分为多个模块呢?答案就是二维数组

首先将当前的页码存储起来(默认为0),当触发下拉加载动作时页码+1,然后以当前页码作为下标存入数组

const currentShowPage=ref(0)
const upper = () => {
  let len = scrollData.value[currentShowPage.value].length - 1;
  let lastNum = scrollData.value[currentShowPage.value][len].data;
  let newArr = [];
  currentShowPage.value += 1;
  for (let index = 1; index <= 10; index++) {
    newArr.push({
      color: getRandomColor(),
      data: lastNum + index,
      index: `index${lastNum + index}`,
    });
  }
  scrollData.value[currentShowPage.value] = newArr;
};

当然别忘了在页面中也需要以二维数组的形式循环数据

<scroll-view style="transform:rotate(180deg)" :scroll-y="true" @scrolltolower="upper">
    <view v-for="(data, index) in scrollData" :key="index">
      <view
         style="transform:rotate(180deg)" 
        :style="{
          backgroundColor: item.color,
          height: &#39;200rpx&#39;,
          lineHeight: &#39;200rpx&#39;,
          textAlign: &#39;center&#39;,
        }"
        v-for="item in data"
        :key="item.index"
      >
        {{ item.data }}
      </view>
    </view>
  </scroll-view>
数据结构的问题解决了,那么接下来就是如何判断数据模块是否超出可视范围

首先我们需要知道每个数据模块的高度,其实很简单,只需要为每个模块定义一个id,然后在数据展示之后根据id获取到该模块的节点信息然后按顺序存储到数组中即可

const pagesHeight = []
onReady(()=>{
    setPageHeight()
})

const upper = () => {
  ...
  nextTick(() => {
    // 每次获取新数据都调用一下
    setPageHeight();
  });
};

const setPageHeight = () => {
  let query = uni.createSelectorQuery();
  query
    .select(`#item-${currentShowPage.value}`)
    .boundingClientRect(res => {
      pagesHeight[currentShowPage.value] = res && res.height;
    })
    .exec();
};

OK,现在我们已经知道每个模块的高度了,然后就是监听模块与可视窗口的交叉范围。这里有两种方法,一种是JS获取可视窗口的高度与模块scrollTop进行差值计算,另一种是使用小程序的createIntersectionObserver方法让程序自行监听交叉区域

这里我展示的是第二种方法,如果对第一种方法感兴趣的朋友可以向上看第二章开头我推荐的《微信小程序虚拟列表》文章

关于createIntersectionObserver方法的使用其实很简单,我们只需要把可视窗口的id以及需要监听的模块id传入即可,详情看官方文档

onReady(() => {
  ...
  observer(currentShowPage.value);
});
const upper = () => {
  ...
  nextTick(() => {
    // 每次获取新数据都调用一下
    observer();
  });
};

// 允许渲染的数组下标,需要设置默认值
const visiblePagesList = ref([-1,0,1])
const observer = pageNum => {
  const observeView = wx
    .createIntersectionObserver()
    .relativeTo("#scroll", { top: 0, bottom: 0 });
  observeView.observe(`#item-${pageNum}`, res => {
    if (res.intersectionRatio > 0) visiblePagesList.value = [pageNum - 1, pageNum, pageNum + 1];
  });
};

最后就是在页面中判断该模块是否允许被渲染(也就是是否存储在visiblePagesList数组中),这里就很简单了,只需要写一个方法在页面中调用即可

<scroll-view id="scroll" class="scroll" :scroll-y="true" @scrolltolower="upper">
    <view v-for="(data, index) in scrollData" :key="index" :id="&#39;item-&#39; + index">
      <template v-if="includePage(index)">
        <view
          class="scroll-item"
          :style="{
            ...
          }"
          v-for="item in data"
          :key="item.index"
        >
          {{ item.data }}
        </view>
      </template>
      <view v-else :style="{ height: pagesHeight[index] }"></view>
    </view>
  </scroll-view>
const includePage = index => {
  return visiblePagesList.value.indexOf(index) > -1;
};

来看看效果如何

5.gif

额...似乎没有太大区别,那我们看看页面结构到底也没有将可视区域外的内容切换为空白view

6.gif

成功!

3、功能调整

聊天室原本还有回底功能等,也不能忘了加上

这个部分就比较简单了,只需要直接使用scroll-viewscroll-top属性,然后通过在scroll回调中动态记载scroll-top的值即可

下面是部分代码

<scroll-view
    id="scroll"
    class="scroll"
    :scroll-y="true"
    :scroll-top="currentTop"
    @scroll="handle_scroll"
    @scrolltolower="upper"
  >
  ...
  </scroll-view>
  <view v-show="showGoBottom" class="go-back-btn" @click="handle_goBottom">回底</view>
let scrollTop;
const currentTop = ref(0);
const showGoBottom = ref(false);
const handle_scroll = throttle(event => {
  scrollTop = event[0].detail.scrollTop;
  if (scrollTop > 300) {
    showGoBottom.value = true;
  }
}, 100);
const handle_goBottom = () => {
  currentTop.value = scrollTop;
  nextTick(() => {
    currentTop.value = 0;
  });
  showGoBottom.value = false;
};

大功告成~

最后附上demo仓库

https://gitee.com/huang-qihao123/virtual-list-demo

推荐:《uniapp教程

以上是聊聊uniapp的scroll-view下拉加载的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文转载于:掘金社区。如有侵权,请联系admin@php.cn删除
您如何在不同平台(例如移动,Web)上调试问题?您如何在不同平台(例如移动,Web)上调试问题?Mar 27, 2025 pm 05:07 PM

本文讨论了有关移动和网络平台的调试策略,突出显示了Android Studio,Xcode和Chrome DevTools等工具,以及在OS和性能优化的一致结果的技术。

哪些调试工具可用于Uniapp开发?哪些调试工具可用于Uniapp开发?Mar 27, 2025 pm 05:05 PM

文章讨论了用于Uniapp开发的调试工具和最佳实践,重点关注Hbuilderx,微信开发人员工具和Chrome DevTools等工具。

您如何为Uniapp应用程序执行端到端测试?您如何为Uniapp应用程序执行端到端测试?Mar 27, 2025 pm 05:04 PM

本文讨论了跨多个平台的Uniapp应用程序的端到端测试。它涵盖定义测试方案,选择诸如Appium和Cypress之类的工具,设置环境,写作和运行测试,分析结果以及集成

您可以在Uniapp应用程序中执行哪些不同类型的测试?您可以在Uniapp应用程序中执行哪些不同类型的测试?Mar 27, 2025 pm 04:59 PM

本文讨论了针对Uniapp应用程序的各种测试类型,包括单元,集成,功能,UI/UX,性能,跨平台和安全测试。它还涵盖了确保跨平台兼容性,并推荐Jes等工具

Uniapp中有哪些常见的性能反版?Uniapp中有哪些常见的性能反版?Mar 27, 2025 pm 04:58 PM

本文讨论了UNIAPP开发中的共同绩效抗模式,例如过度的全球数据使用和效率低下的数据绑定,并提供策略来识别和减轻这些问题,以提高应用程序性能。

您如何使用分析工具来识别uniapp中的性能瓶颈?您如何使用分析工具来识别uniapp中的性能瓶颈?Mar 27, 2025 pm 04:57 PM

本文讨论了使用分析工具来识别和解决Uniapp中的性能瓶颈,重点是设置,数据分析和优化。

您如何在Uniapp中优化网络请求?您如何在Uniapp中优化网络请求?Mar 27, 2025 pm 04:52 PM

本文讨论了在UNIAPP中优化网络请求的策略,重点是减少延迟,实施缓存以及使用监视工具来增强应用程序性能。

如何优化Uniapp中的Web性能的图像?如何优化Uniapp中的Web性能的图像?Mar 27, 2025 pm 04:50 PM

本文讨论了通过压缩,响应式设计,懒惰加载,缓存和使用WebP格式来优化Uniapp中的图像,以更好地进行Web性能。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
3 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

EditPlus 中文破解版

EditPlus 中文破解版

体积小,语法高亮,不支持代码提示功能

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器