最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解Vue如何手寫一個(gè)虛擬列表

 更新時(shí)間:2024年04月19日 10:22:03   作者:吃肉不吃皮  
虛擬列表是一種優(yōu)化長(zhǎng)列表渲染的技術(shù),它可以在保持流暢性的同時(shí),渲染大量的數(shù)據(jù),本文主要介紹了如何使用vue手寫一個(gè)虛擬列表,感興趣的可以了解下

前言

何為虛擬列表?

回答這個(gè)問(wèn)題先想一下,對(duì)于返回的幾千上萬(wàn)條列表數(shù)據(jù),作為前端會(huì)如何渲染?

分頁(yè)唄,最開(kāi)始想到的就是分頁(yè)。但是,萬(wàn)一接口沒(méi)做分頁(yè)呢?好,就算后端做分頁(yè)了,那么用戶在瀏覽到第幾千條、第幾萬(wàn)條數(shù)據(jù)時(shí)前端難道要把這第幾千條、幾萬(wàn)條的DOM都渲染出來(lái)嗎?顯然是很消耗性能的(畢竟如此多的DOM,而且每個(gè)DOM內(nèi)部都有其他樣式細(xì)節(jié))如何優(yōu)化?此時(shí)就可以用到虛擬列表了

虛擬列表是一種優(yōu)化長(zhǎng)列表渲染的技術(shù),它可以在保持流暢性的同時(shí),渲染大量的數(shù)據(jù)。

在傳統(tǒng)的列表渲染中,如果列表非常長(zhǎng),會(huì)導(dǎo)致渲染時(shí)間過(guò)長(zhǎng)(前面所說(shuō)的會(huì)有幾千幾萬(wàn)個(gè)DOM),頁(yè)面卡頓,用戶體驗(yàn)變得非常差。而虛擬列表則是只渲染可見(jiàn)區(qū)域內(nèi)的數(shù)據(jù),而非全部渲染,這樣就可以大大提高渲染效率,保持頁(yè)面流暢性

常見(jiàn)場(chǎng)景

商品列表、社交列表...(暫時(shí)想到這兩個(gè))

手寫虛擬列表

進(jìn)行虛擬列表的實(shí)現(xiàn)之前先搞清楚一個(gè)問(wèn)題:

是什么造成了這么多數(shù)據(jù)在渲染時(shí)產(chǎn)生卡頓?是數(shù)據(jù)數(shù)量太多引起的嗎?

準(zhǔn)確來(lái)說(shuō),應(yīng)該是是由于要渲染的DOM太多造成的卡頓。數(shù)據(jù)本身只是數(shù)據(jù),對(duì)于拿到的幾千上萬(wàn)條數(shù)據(jù)它本身的大小對(duì)于內(nèi)存來(lái)說(shuō)只能說(shuō)是冰山一角吧

虛擬列表的原理

數(shù)據(jù)我還是這么多數(shù)據(jù),但是我不一次性渲染這么多數(shù)據(jù),我只渲染其中的一小部分(比如十條),這樣當(dāng)用戶滾動(dòng)的時(shí)候就重復(fù)變化這一小部分的DOM的渲染效果。這樣就能從原先幾千上萬(wàn)個(gè)DOM變成現(xiàn)在的十個(gè),減少了一個(gè)量級(jí),減輕了渲染的壓力。而這一小部分顯示的區(qū)域暫稱之為視圖區(qū)域吧

審查元素,大致的效果如圖:

賊長(zhǎng)的這部分是所有的數(shù)據(jù)的盒子所占的大小,但是每次只控制小部分?jǐn)?shù)據(jù)在上面的盒子進(jìn)行顯示

虛擬列表的實(shí)現(xiàn)

怎么實(shí)現(xiàn)上面的效果?這里用到了固定定位和絕對(duì)定位

<script lang='ts' setup>
  type Item = {
    id: number
    name: string
  }
  const allListData = ref<Item[]>([])	// 存放十萬(wàn)條數(shù)據(jù)
  const itemHeight = ref(40) // 每一條(項(xiàng))的高度
  const count = ref(10) // 一屏展示幾條數(shù)據(jù)
  const startIndex = ref(0) // 開(kāi)始位置的索引
  const endIndex = ref(10) // 結(jié)束位置的索引
  const topVal = ref(0) // 父元素滾動(dòng)位置

  // 計(jì)算展示的列表
  const showListData = computed(() => allListData.value.slice(startIndex.value, endIndex.value))

  // 模擬十萬(wàn)條數(shù)據(jù)
  const getData = async () => {
    for (let i = 0; i < 10000; i++) {
      allListData.value.push({ name: `第${i}條數(shù)據(jù)`, id: i })
    }
  }

  // 初始化加載
  onMounted(() => {
    getData()
  })

  // 虛擬列表視口區(qū)域的組件實(shí)例
  const viewport = ref<HTMLDivElement>()

    const handleScroll = () => {
      console.log('滾動(dòng)了')
      // 非空判斷
      if (!viewport.value) return
      // 獲取滾動(dòng)距離(這里通過(guò)組件實(shí)例獲取的,當(dāng)然也可以通過(guò)在該事件的事件參數(shù)中拿到)
      const scrollTop = viewport.value.scrollTop
      // 計(jì)算起始下標(biāo)和結(jié)束下標(biāo),用于 computed 計(jì)算
      startIndex.value = Math.floor(scrollTop / itemHeight.value)
      endIndex.value = startIndex.value + count.value
      // 動(dòng)態(tài)更改定位的 top 值,動(dòng)態(tài)展示相應(yīng)內(nèi)容
      topVal.value = viewport.value.scrollTop
    }
</script>

<template>
  <!-- 虛擬列表容器 -->
  <div
    class="viewport"
    ref="viewport"
    :style="{ height: 10條數(shù)據(jù)撐開(kāi)的高度 }"
    >
    <!-- 占位元素,高度為所有的數(shù)據(jù)的總高度 -->
    <div
      class="placeholder"
      :style="{ height:itemHeight * count + 'px' }"
      ></div>
    <!-- 視圖區(qū),展示10條數(shù)據(jù),注意其定位的top值是變化的 -->
    <div class="list" :style="{ top: topVal + 'px' }">
      <!-- 每一條(項(xiàng))數(shù)據(jù) -->
      <div
        v-for="item in showListData"
        :key="item.id"
        class="item"
        :style="{ height: itemHeight + 'px' }"
        >
        {{ item.name }}
      </div>
    </div>
  </div>
</template>

  <style scoped lang="scss">
  .viewport {
  box-sizing: border-box;
  width: 240px;
  border: solid 1px #000000;
  // 開(kāi)啟滾動(dòng)條
  overflow-y: auto;
  // 開(kāi)啟相對(duì)定位
  position: relative;
  .list {
  width: 100%;
  height: auto;
  // 搭配使用絕對(duì)定位
  position: absolute;
  top: 0;
  left: 0;
  .item {
  box-sizing: border-box;
  width: 100%;
  height: 40px;
  line-height: 40px;
  text-align: center;
  // 隔行變色
  &:nth-child(even) {
  background: skyblue;
  }
  &:nth-child(odd) {
  background: #fff;
  }
  }
  }
  }
</style>

一開(kāi)始視圖區(qū)域的top值為0,剛好在最頂端,監(jiān)聽(tīng)滾動(dòng)事件,當(dāng)滾動(dòng)時(shí)實(shí)時(shí)改變top值以及該區(qū)域內(nèi)渲染的數(shù)據(jù),從而實(shí)現(xiàn)了虛擬列表

視圖區(qū)域的top值為什么要?jiǎng)討B(tài)監(jiān)聽(tīng)?試想一下,現(xiàn)在所有數(shù)據(jù)的總高度為1000px,視圖區(qū)域?yàn)?00px,當(dāng)用戶滾動(dòng)到500px時(shí),如果視圖區(qū)域的top值不動(dòng)態(tài)綁定,那么視圖區(qū)域還停留在top=0(也就是最頂端處),那肯定就看不到最新的視圖了

到此這篇關(guān)于詳解Vue如何手寫一個(gè)虛擬列表的文章就介紹到這了,更多相關(guān)Vue虛擬列表內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • vue中的.sync修飾符用法及原理分析

    vue中的.sync修飾符用法及原理分析

    這篇文章主要介紹了vue中的.sync修飾符用法及原理分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • vue2中插槽(slot)的基本使用規(guī)范

    vue2中插槽(slot)的基本使用規(guī)范

    插槽(Slot)是Vue提出來(lái)的一個(gè)概念,正如名字一樣,插槽用于決定將所攜帶的內(nèi)容,插入到指定的某個(gè)位置,從而使模板分塊,具有模塊化的特質(zhì)和更大的重用性,下面這篇文章主要給大家介紹了關(guān)于vue2中插槽(slot)的基本使用規(guī)范的相關(guān)資料,需要的朋友可以參考下
    2022-03-03
  • vue如何根據(jù)權(quán)限生成動(dòng)態(tài)路由、導(dǎo)航欄

    vue如何根據(jù)權(quán)限生成動(dòng)態(tài)路由、導(dǎo)航欄

    這篇文章主要介紹了vue如何根據(jù)權(quán)限生成動(dòng)態(tài)路由、導(dǎo)航欄,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • vue中uni-app 實(shí)現(xiàn)小程序登錄注冊(cè)功能

    vue中uni-app 實(shí)現(xiàn)小程序登錄注冊(cè)功能

    這篇文章主要介紹了uni-app 實(shí)現(xiàn)小程序登錄注冊(cè)功能,文中給大家介紹了實(shí)現(xiàn)思路,以及vuex和本地緩存的區(qū)別,需要的朋友可以參考下
    2019-10-10
  • Vue2實(shí)現(xiàn)組件props雙向綁定

    Vue2實(shí)現(xiàn)組件props雙向綁定

    這篇文章主要為大家詳細(xì)介紹了如何在Vue2中實(shí)現(xiàn)組件props雙向綁定,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • 解決vue.js提交數(shù)組時(shí)出現(xiàn)數(shù)組下標(biāo)的問(wèn)題

    解決vue.js提交數(shù)組時(shí)出現(xiàn)數(shù)組下標(biāo)的問(wèn)題

    今天小編就為大家分享一篇解決vue.js提交數(shù)組時(shí)出現(xiàn)數(shù)組下標(biāo)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-11-11
  • vue實(shí)現(xiàn)打印指定組件內(nèi)容的示例詳解

    vue實(shí)現(xiàn)打印指定組件內(nèi)容的示例詳解

    這篇文章主要和大家分享一下vue中打印指定組件內(nèi)容,多頁(yè)打印自動(dòng)適配紙張大小打印的方案,文中的示例代碼講解詳細(xì),需要的可以參考一下
    2024-03-03
  • 離線搭建vue環(huán)境運(yùn)行項(xiàng)目完整步驟

    離線搭建vue環(huán)境運(yùn)行項(xiàng)目完整步驟

    這篇文章主要給大家介紹了關(guān)于離線搭建vue環(huán)境運(yùn)行項(xiàng)目的相關(guān)資料,文中通過(guò)實(shí)例代碼以及圖文介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用vue具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2023-06-06
  • VITE+VUE3跨域環(huán)境變量配置全過(guò)程

    VITE+VUE3跨域環(huán)境變量配置全過(guò)程

    文章介紹了如何在Vue項(xiàng)目中使用Vite管理環(huán)境變量,并根據(jù)不同的環(huán)境(開(kāi)發(fā)、生產(chǎn))設(shè)置相應(yīng)的變量,它還指導(dǎo)如何在Vue文件和vite.config.ts中獲取這些環(huán)境變量,并在生產(chǎn)環(huán)境中處理跨域問(wèn)題
    2026-01-01
  • ElementUI之Message功能拓展詳解

    ElementUI之Message功能拓展詳解

    這篇文章主要介紹了ElementUI之Message功能拓展詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10

最新評(píng)論

叙永县| 湖州市| 科技| 宁强县| 宁海县| 讷河市| 木兰县| 鄂托克旗| 于都县| 阜阳市| 凤冈县| 重庆市| 台东县| 托克托县| 青岛市| 丰县| 大港区| 黎城县| 牡丹江市| 正定县| 朝阳县| 德令哈市| 凤山县| 罗江县| 普陀区| 威远县| 张家港市| 尖扎县| 信丰县| 榆林市| 哈尔滨市| 皋兰县| 静安区| 襄汾县| 江门市| 鹤壁市| 卢氏县| 铁岭县| 广丰县| 英德市| 东海县|