Heim  >  Artikel  >  Web-Frontend  >  Lassen Sie uns über das Dropdown-Laden der Scroll-Ansicht in Uniapp sprechen

Lassen Sie uns über das Dropdown-Laden der Scroll-Ansicht in Uniapp sprechen

青灯夜游
青灯夜游nach vorne
2022-07-14 21:07:083587Durchsuche

Lassen Sie uns über das Dropdown-Laden der Scroll-Ansicht in Uniapp sprechen

Vor kurzem arbeite ich an einem Live-Broadcast-Modul des WeChat Mini-Programms. Die Chatroom-Funktion im Modul verwendet scroll-view + one-. dimensionales Array Es wird in Form von Code> angezeigt und es wurde keine Optimierung durchgeführt, was zu einer schlechten Benutzererfahrung führt微信小程序直播模块,模块里的聊天室功能是用scroll-view + 一维数组的形式展示的,而且也没有进行任何的优化,导致用户的体验感比较差

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

Lassen Sie uns über das Dropdown-Laden der Scroll-Ansicht in Uniapp sprechen

肉眼可见的蛋疼~

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

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>这是一个直播画面</view>
  <scroll-view>
    <view>
      {{ item.data }}
    </view>
  </scroll-view>
const scrollIntoView = ref("index1");
const upper = () => {
  let lastNum = scrollData.value[0].data;
  let newArr = [];
  for (let index = 1; index  {
    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属性去掉,就会得到这样的效果?

Lassen Sie uns über das Dropdown-Laden der Scroll-Ansicht in Uniapp sprechen

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

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

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

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

Lassen Sie uns über das Dropdown-Laden der Scroll-Ansicht in Uniapp sprechen

下面是目前的聊天室

Simulieren Sie zunächst die Chatroom-Situation zuvor Optimierung

Lassen Sie uns über das Dropdown-Laden der Scroll-Ansicht in Uniapp sprechenLassen Sie uns über das Dropdown-Laden der Scroll-Ansicht in Uniapp sprechen

🎜 Sichtbarer Ei-Schmerz~🎜 🎜Ohne Optimierung geht es aber nicht. Aber bevor ich anfange, ist es meiner Meinung nach notwendig, die Optimierungsschritte in die folgenden zwei Punkte aufzuteilen?🎜🎜🎜Nicht mehr mit scroll-in-viewAnkerpunkt setzen🎜🎜Da die alte Version in Form von scroll-view + eindimensionales Array implementiert wurde, ergab sich dies Die Seite ist immer voll, nachdem die Daten hinzugefügt wurden. Es wird Die letzte Nachricht nach dem Laden anstelle von Die letzte Nachricht vor dem Laden angezeigt, sodass der vorherige Entwickler verwendet hat scroll-into-view >Das Attribut dient als Rückgabeankerpunkt, nachdem die Daten geladen wurden. Da jedoch der Ankerpunkt und der Daten erfolgt nicht gleichzeitig. Dies führt zum Bounce-Phänomen🎜🎜🎜Verarbeitung großer Datenmengen🎜🎜 Da es sich um eine Chatroom-Funktion handelt, ist es unvermeidlich, eine große Menge an Benutzerkonversationen, Bildern und anderen Inhalten zu laden, und weil scroll-view selbst nicht dafür geeignet ist Laden einer großen Datenmenge (es ist zu schade, an andere Methoden zu denken), daher muss am Lade- und Anzeigeteil gearbeitet werden🎜🎜🎜Zusätzliche Funktionsverarbeitung🎜🎜Der Chatroom verfügte ursprünglich über Funktionen wie Zurück nach unten, daher können die ursprünglichen Funktionen nach Abschluss der Optimierung nicht ignoriert werden🎜🎜OK, um zu beginnen~🎜

1. Scroll-Ansicht umkehren

🎜Warum scrollen umkehren? Was ist mit der Ansicht? Aus dem ersten Punkt oben können wir ersehen, dass, wenn Daten in positiver Reihenfolge eingefügt werden müssen, es zwangsläufig zu einer Situation kommt, in der die nachfolgenden Daten nach dem Laden der Daten nicht angezeigt werden können, aber wir wollen Um diese Situation zu lösen, müssen Sie das Attribut scroll-into-view verwenden. Wenn Sie dieses Problem also vollständig lösen müssen, müssen Sie an der Wurzel des Problems scroll-view beginnen 🎜🎜Zuerst Code vor dem Ändern ?🎜
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 <pre class="brush:php;toolbar:false"><scroll-view>
    <view>
      <view>
        {{ item.data }}
      </view>
    </view>
  </scroll-view>
🎜Dann versuchen wir zuerst die Scroll-Ansicht umzukehren, aber es hat keine Auswirkung🎜🎜Zuerst müssen wir es tun Legen Sie scroll-view das Attribut des vorherigen transform:rotate(180deg) fest und wenden Sie dann dasselbe Attribut auf die internen untergeordneten Elemente an. Vergessen Sie nicht, das array, das auch die Daten speichert, das Wichtigste ist, das Attribut scroll-into-view aus scroll-view zu entfernen, und Sie werden es tun Erhalten Sie diesen Effekt? >🎜🎜Es gibt auch die Bildlaufleiste<. die position von> befindet sich auf der linken Seite. Bei Bedarf können Sie sie mit dem <code>CSS-Attribut entfernen oder selbst simulieren Ist der CSS-Stil zum Entfernen der Bildlaufleiste? 🎜
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();
};
🎜 Dies ist nur der erste Schritt. Der nächste Schritt ist wie man Daten herunterzieht und lädtCode>. 🎜🎜Zu diesem Zeitpunkt befindet sich unsere Bildlaufansicht in einem invertierten-Zustand, was bedeutet, dass die Oberseite unten und die Unterseite die Oberseiteist > (lassen Sie es beiseite Zungenbrecher), daher muss die zuvor verwendete scrolltoupper top-Methode durch scrolltolower bottom-Methode ersetzt werden, um ein „Pull-Down-Laden“ zu erreichen🎜🎜Lassen Sie uns über das Dropdown-Laden der Scroll-Ansicht in Uniapp sprechen🎜🎜Das Folgende ist der aktuelle ChatroomSieht viel besser aus🎜🎜🎜🎜

2、大量数据的处理

处理完回弹问题后,就需要考虑如何处理大量数据。由于uni-app官方也在文档中提到scroll-view加载大批量数据的时候性能较差,但无奈手头上也没有别的办法,只能死马当活马医了

我第一个想法就是非常经典的虚拟列表,但是此前所看的很多关于虚拟列表的文章都是在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 <p>当然别忘了在页面中也需要以<code>二维数组</code>的形式循环数据</p><pre class="brush:php;toolbar:false"><scroll-view>
    <view>
      <view>
        {{ 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>
    <view>
      <template>
        <view>
          {{ item.data }}
        </view>
      </template>
      <view></view>
    </view>
  </scroll-view>
const includePage = index => {
  return visiblePagesList.value.indexOf(index) > -1;
};

来看看效果如何

Lassen Sie uns über das Dropdown-Laden der Scroll-Ansicht in Uniapp sprechen

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

Lassen Sie uns über das Dropdown-Laden der Scroll-Ansicht in Uniapp sprechen

成功!

3、功能调整

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

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

下面是部分代码

<scroll-view>
  ...
  </scroll-view>
  <view>回底</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教程

Das obige ist der detaillierte Inhalt vonLassen Sie uns über das Dropdown-Laden der Scroll-Ansicht in Uniapp sprechen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:juejin.cn. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen