Maison  >  Article  >  interface Web  >  Parlons du chargement déroulant de la vue déroulante d'Uniapp

Parlons du chargement déroulant de la vue déroulante d'Uniapp

青灯夜游
青灯夜游avant
2022-07-14 21:07:083654parcourir

Parlons du chargement déroulant de la vue déroulante d'Uniapp

Récemment, je travaille sur un Module de diffusion en direct du WeChat Mini Program La fonction de salle de discussion dans le module utilise scroll-view + one-. tableau dimensionnel Il est affiché sous forme de code>, et aucune optimisation n'a été effectuée, ce qui entraîne une mauvaise expérience utilisateur微信小程序直播模块,模块里的聊天室功能是用scroll-view + 一维数组的形式展示的,而且也没有进行任何的优化,导致用户的体验感比较差

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

Parlons du chargement déroulant de la vue déroulante dUniapp

肉眼可见的蛋疼~

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

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属性去掉,就会得到这样的效果?

Parlons du chargement déroulant de la vue déroulante dUniapp

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

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

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

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

Parlons du chargement déroulant de la vue déroulante dUniapp

下面是目前的聊天室

Simulez d'abord la situation du chat avant optimisation

Parlons du chargement déroulant de la vue déroulante dUniappParlons du chargement déroulant de la vue déroulante dUniapp

🎜 Douleur d'œuf visible~🎜 🎜Mais l'optimisation doit encore être faite. C'est impossible sans optimisation. Mais avant de commencer, je pense qu'il est nécessaire de diviser les étapes d'optimisation en deux points suivants ?🎜🎜🎜1. en utilisant défilement vers la vueDéfinir le point d'ancrage🎜🎜Étant donné que l'ancienne version était implémentée sous la forme de vue par défilement + tableau unidimensionnel, cela résultait dans la page étant toujours pleine après l'ajout des données, Le dernier message après le chargement sera affiché à la place de Le dernier message avant le chargement, le développeur précédent a donc utilisé . scroll-into-view >L'attribut sert de point d'ancrage de retour après le chargement des données. Cependant, depuis la commutation du point d'ancrage et du <. code>le chargement des données ne se produit pas simultanément, cela conduit à un phénomène de rebond🎜🎜🎜2. Parce qu'il s'agit d'une fonction de chat room, il est donc inévitable de charger une grande quantité de conversations d'utilisateurs, d'images et d'autres contenus, et parce que la vue par défilement elle-même n'est pas adaptée à charger une grande quantité de données (c'est dommage de penser à d'autres méthodes), il faut donc les charger dans les données. Travailler sur la partie chargement et affichage🎜🎜🎜3. /strong>🎜🎜Le salon de discussion avait à l'origine des fonctions telles que Retour en bas, donc une fois l'optimisation terminée, les fonctions d'origine ne peuvent pas être ignorées🎜🎜OK pour commencer~🎜

1. Inverser la vue de défilement

🎜Pourquoi inverser le défilement ? Et la vue ? À partir du premier point ci-dessus, nous pouvons voir que si les données doivent être insérées dans un ordre positif, alors il y aura inévitablement une situation où les données suivantes ne pourront pas être affichées après le chargement des données, mais nous voulons pour résoudre cette situation. Vous devez utiliser l'attribut scroll-into-view, donc si vous devez résoudre complètement ce problème, vous devez commencer par la racine du problème scroll-view. 🎜🎜Tout d'abord, Coder avant de modifier ?🎜
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>
🎜Ensuite, essayons d'abord inverser la vue défilante mais cela n'a aucun effet🎜🎜Nous devons d'abord définissez scroll-view L'attribut du transform:rotate(180deg) précédent, puis appliquez le même attribut aux éléments enfants internes. N'oubliez pas d'inverser le <. code>tableau qui stocke également les données, la chose la plus importante est de supprimer l'attribut scroll-into-view sur scroll-view et vous le ferez. obtenir cet effet ?🎜🎜Parlons du chargement déroulant de la vue déroulante dUniapp🎜🎜Il y a aussi la scroll bar est à gauche Si nécessaire, vous pouvez utiliser l'attribut <code>CSS pour la supprimer, ou la simuler vous-même. est-ce que le style CSS pour supprimer la barre de défilement ?🎜
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();
};
🎜 Ce n'est que la première étape. L'étape suivante est comment extraire et charger les donnéescode>. 🎜🎜À l'heure actuelle, notre vue défilante est dans un état inversé, ce qui signifie que le haut est le bas et le bas est le haut (laissez-le de côté Vire-langue), donc la méthode scrolltopper top précédemment utilisée doit être remplacée par la méthode scrolltolower bottom pour obtenir un "chargement déroulant"🎜🎜Parlons du chargement déroulant de la vue déroulante dUniapp🎜🎜Ce qui suit est le courant Salon de discussionVous avez l'air beaucoup mieux🎜🎜🎜🎜

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;
};

来看看效果如何

Parlons du chargement déroulant de la vue déroulante dUniapp

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

Parlons du chargement déroulant de la vue déroulante dUniapp

成功!

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教程

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer