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

基于Vue實(shí)現(xiàn)封裝一個虛擬列表組件

 更新時間:2023年03月07日 10:00:13   作者:前端小小夢  
正常情況下,我們對于數(shù)據(jù)都會分頁加載,最近項(xiàng)目中確實(shí)遇到了不能分頁的場景,如果不分頁,頁面渲染幾千條數(shù)據(jù)就會感知到卡頓,使用虛擬列表就勢在必行了。本文主要介紹了如何基于Vue實(shí)現(xiàn)封裝一個虛擬列表組件,感興趣的可以了解一下

正常情況下,我們對于數(shù)據(jù)都會分頁加載,最近項(xiàng)目中確實(shí)遇到了不能分頁的場景,如果不分頁,頁面渲染幾千條數(shù)據(jù)就會感知到卡頓,使用虛擬列表就勢在必行了,為了增加復(fù)用性,封裝成了組件。

組件效果

使用方法

<template>
  <div>
    <div class="virtual-list-md-wrap">
      <hub-virtual-list :allData="data" itemHeight="70" :virtualData.sync="virtualData">
        <div v-for="(item, index) in virtualData" class="item">
         {{ item  }}
         <el-button type="primary" size="mini" plain @click="deleteItem(item)">刪除</el-button>
        </div>
      </hub-virtual-list>
    </div>
  </div>
  
</template>
<script>
export default {
  data() {
    return {
      data: [],
      virtualData: []
    }
  },
  created() {
    setTimeout(() => {
      this.addData()
    }, 1000)
  },
  watch: {
  },
  methods: {
    addData() {
      for(let i = 0; i <= 100000; i ++) {
        this.$set(this.data, i, i)
      }
    },
    deleteItem(index) {
      this.data = this.data.filter((item) => item !== index)
    }
  }
}
</script>
<style>
.virtual-list-md-wrap {
  height: 500px;
  background-color: #FFFAF0;
}
.item {
  border-bottom: 1px solid #666;
  padding: 20px;
  text-align: center;
}
</style>

屬性

參數(shù)說明類型可選值默認(rèn)值
allData全部數(shù)據(jù)Array-[]
virtualData虛擬數(shù)據(jù)Array-[]
itemHeight每行的高度,用于計(jì)算滾動距離Number, String-30

插槽

插槽名說明
-自定義默認(rèn)內(nèi)容,即主體區(qū)域

封裝過程

首先梳理我想要的組件效果:

  • 滾動條正常顯示
  • 加載渲染大量數(shù)據(jù)不卡頓
  • 能對列表數(shù)據(jù)進(jìn)行操作增刪等

滾動條正常顯示

需要把顯示框分為3部分:顯示高度,全部高度,虛擬數(shù)據(jù)高度

大概的比例是這樣的

為達(dá)到滾動條的效果,在最外層顯示高度設(shè)置overflow: auto可以把滾動條撐出來,全部高度則設(shè)置position: absolute;z-index: -1;height: auto;,虛擬數(shù)據(jù)高度則設(shè)置position: absolute; height: auto;

整體樣式代碼如下

<template>
  <div class="hub-virtual-list">
    <!-- 顯示高度 -->
    <div ref="virtualList" class="hub-virtual-list-show-height" @scroll="scrollEvent($event)">
      <!-- 全部高度,撐出滾動條 -->
      <div class="hub-virtual-list-all-height" :style="{height: allHeight + 'px'}"/>
      <!-- 存放顯示數(shù)據(jù) -->
      <div class="virtual-list" :style="{ transform: getTransform }"/>
    </div>
  </div>
</template>

<style lang="scss" scoped>
.hub-virtual-list {
  height: 100%;
  &-show-height {
    position: relative;
    overflow: auto;
    height: 100%;
    -webkit-overflow-scrolling: touch;
  }
  &-all-height {
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    z-index: -1;
    height: auto;
  }
  .virtual-list {
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    height: auto;
  }
}
</style>

加載渲染大量數(shù)據(jù)不卡頓

如果想要渲染不卡頓,就得只加載顯示區(qū)域的虛擬數(shù)據(jù),虛擬數(shù)據(jù)的更新邏輯為:用startIndexendIndex標(biāo)志虛擬數(shù)據(jù)的起始索引和結(jié)束索引,在滾動條滑動時,通過計(jì)算滑動的距離去更新startIndexendIndex。另外用offset標(biāo)記偏移量,對虛擬數(shù)據(jù)區(qū)域設(shè)置transform: translate3d(0, ${this.offset}px, 0)跟著滾動條去移動

核心部分代碼如下

scrollEvent(e) {
  const scrollTop = this.$refs.virtualList.scrollTop
  // 起始索引 = 滾動距離 / 每項(xiàng)高度
  this.startIndex = Math.floor(scrollTop / this.itemHeight)
  // 結(jié)束索引 = 開始索引 + 可見數(shù)量
  this.endIndex = this.startIndex + this.visibleCount
  // 偏移量 = 滾動距離
  this.offset = scrollTop - (scrollTop % this.itemHeight)
}

能對列表數(shù)據(jù)進(jìn)行操作增刪等

如果想要在數(shù)據(jù)里添加操作按鈕,則需要在封裝組件時設(shè)置插槽,且需要把虛擬數(shù)據(jù)同步給父組件

設(shè)置插槽

<!-- 顯示高度 -->
<div ref="virtualList" class="hub-virtual-list-show-height" @scroll="scrollEvent($event)">
  <!-- 全部高度,撐出滾動條 -->
  <div class="hub-virtual-list-all-height" :style="{height: allHeight + 'px'}"/>
  <!-- 存放顯示數(shù)據(jù) -->
  <div class="virtual-list" :style="{ transform: getTransform }">
    <!-- 設(shè)置插槽 -->
    <slot/> 
  </div>
</div>

滾動時把虛擬數(shù)據(jù)同步給父組件

scrollEvent(e) {
  const scrollTop = this.$refs.virtualList.scrollTop
  // 起始索引 = 滾動距離 / 每項(xiàng)高度
  this.startIndex = Math.floor(scrollTop / this.itemHeight)
  // 結(jié)束索引 = 開始索引 + 可見數(shù)量
  this.endIndex = this.startIndex + this.visibleCount
  // 偏移量 = 滾動距離
  this.offset = scrollTop - (scrollTop % this.itemHeight)
  // 同步父組件數(shù)據(jù)
  this.inVirtualData = this.allData.slice(this.startIndex, this.endIndex)
  this.$emit('update:virtualData', this.inVirtualData)
}

完整代碼

<template>
  <div class="hub-virtual-list">
    <!-- 顯示高度 -->
    <div ref="virtualList" class="hub-virtual-list-show-height" @scroll="scrollEvent($event)">
      <!-- 全部高度,撐出滾動條 -->
      <div class="hub-virtual-list-all-height" :style="{height: allHeight + 'px'}"/>
      <!-- 存放顯示數(shù)據(jù) -->
      <div class="virtual-list" >
        <slot/>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'hub-virtual-list',
  props: {
    // 全部數(shù)據(jù)
    allData: {
      type: Array,
      default: () => []
    },
    // 虛擬數(shù)據(jù)
    virtualData: {
      type: Array,
      default: () => []
    },
    // 每項(xiàng)高度
    itemHeight: {
      type: [Number, String],
      default: '30'
    },
    // 每項(xiàng)樣式
    itemStyle: {
      type: Object,
      default: () => {}
    }
  },
  data() {
    return {
      // 起始索引
      startIndex: 0,
      // 結(jié)束索引
      endIndex: null,
      // 偏移量,計(jì)算滾動條
      offset: 0,
      inVirtualData: []
    }
  },
  computed: {
    // 所有高度
    allHeight() {
      // 每項(xiàng)高度 * 項(xiàng)數(shù)
      return this.itemHeight * this.allData.length
    },
    // 可見數(shù)量
    visibleCount() {
      // 可見高度 / 每項(xiàng)高度
      return Math.ceil(this.showHeight / this.itemHeight)
    },
    // 顯示數(shù)據(jù)的偏移量
    getTransform() {
      return `translate3d(0, ${this.offset}px, 0)`
    }
  },
  watch: {
    allData: {
      handler() {
        this.inVirtualData = this.allData.slice(this.startIndex, this.endIndex)
        this.$emit('update:virtualData', this.inVirtualData)
      },
      deep: true
    }
  },
  mounted() {
    this.showHeight = this.$el.clientHeight
    this.startIndex = 0
    this.endIndex = this.startIndex + this.visibleCount
  },
  methods: {
    scrollEvent(e) {
      const scrollTop = this.$refs.virtualList.scrollTop
      // 起始索引 = 滾動距離 / 每項(xiàng)高度
      this.startIndex = Math.floor(scrollTop / this.itemHeight)
      // 結(jié)束索引 = 開始索引 + 可見數(shù)量
      this.endIndex = this.startIndex + this.visibleCount
      // 偏移量 = 滾動距離
      this.offset = scrollTop - (scrollTop % this.itemHeight)
      // 同步父組件數(shù)據(jù)
      this.inVirtualData = this.allData.slice(this.startIndex, this.endIndex)
      this.$emit('update:virtualData', this.inVirtualData)
    }
  }
}
</script>

<style lang="scss" scoped>
.hub-virtual-list {
  height: 100%;
  &-show-height {
    position: relative;
    overflow: auto;
    height: 100%;
    -webkit-overflow-scrolling: touch;
  }
  &-all-height {
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    z-index: -1;
    height: auto;
  }
  .virtual-list {
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    height: auto;
  }
}
</style>

待完善

使用組件時需要設(shè)置itemHeight屬性才能去計(jì)算整體的高度去保證滾動條的準(zhǔn)確性,并且itemHeight的值要和實(shí)際高度相等,不然會出現(xiàn)滾動條滑到底部時出現(xiàn)空白的情況。同時組件僅支持每一行高度固定且相等的情況,對于每行數(shù)據(jù)高度不相等的情況目前還未完善。

以上就是基于Vue實(shí)現(xiàn)封裝一個虛擬列表組件的詳細(xì)內(nèi)容,更多關(guān)于Vue封裝虛擬列表組件的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 使用Plotly.js在Vue中創(chuàng)建交互式散點(diǎn)圖的示例代碼

    使用Plotly.js在Vue中創(chuàng)建交互式散點(diǎn)圖的示例代碼

    Plotly.js是一個功能強(qiáng)大的JavaScript庫,用于創(chuàng)建交互式數(shù)據(jù)可視化,它支持各種圖表類型,包括散點(diǎn)圖、折線圖和直方圖,在Vue.js應(yīng)用程序中,Plotly.js可用于創(chuàng)建動態(tài)且引人入勝的數(shù)據(jù)可視化,本文介紹了使用Plotly.js在Vue中創(chuàng)建交互式散點(diǎn)圖,需要的朋友可以參考下
    2024-07-07
  • Vue3.0之引入Element-plus ui樣式的兩種方法

    Vue3.0之引入Element-plus ui樣式的兩種方法

    本文主要介紹了Vue3.0之引入Element-plus ui樣式的兩種方法,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • vue.js項(xiàng)目使用原生js實(shí)現(xiàn)移動端的輪播圖

    vue.js項(xiàng)目使用原生js實(shí)現(xiàn)移動端的輪播圖

    這篇文章主要為大家介紹了vue.js項(xiàng)目中使用原生js實(shí)現(xiàn)移動端的輪播圖,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-04-04
  • Vue使用自定義指令實(shí)現(xiàn)拖拽行為實(shí)例分析

    Vue使用自定義指令實(shí)現(xiàn)拖拽行為實(shí)例分析

    這篇文章主要介紹了Vue使用自定義指令實(shí)現(xiàn)拖拽行為,結(jié)合實(shí)例形式分析了Vue使用自定義指令實(shí)現(xiàn)拖拽行為具體步驟、原理與操作注意事項(xiàng),需要的朋友可以參考下
    2020-06-06
  • 實(shí)時通信Socket?io的使用示例詳解

    實(shí)時通信Socket?io的使用示例詳解

    這篇文章主要為大家介紹了實(shí)時通信Socket?io的使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • vue2.0中vue-cli實(shí)現(xiàn)全選、單選計(jì)算總價格的實(shí)例代碼

    vue2.0中vue-cli實(shí)現(xiàn)全選、單選計(jì)算總價格的實(shí)例代碼

    本篇文章主要介紹了vue2.0中vue-cli實(shí)現(xiàn)全選、單選計(jì)算總價格的實(shí)例代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • vue 項(xiàng)目中實(shí)現(xiàn)按鈕防抖方法

    vue 項(xiàng)目中實(shí)現(xiàn)按鈕防抖方法

    這篇文章主要介紹了vue 項(xiàng)目中實(shí)現(xiàn)按鈕防抖方法,首先需要新建 .js文件存放防抖方法,引入防抖文件,methods中添加方法,本文結(jié)合示例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-12-12
  • 詳解Vue-cli代理解決跨域問題

    詳解Vue-cli代理解決跨域問題

    本篇文章主要介紹了Vue-cli代理解決跨域問題,詳細(xì)的介紹了Vue如何設(shè)置代理,具有一定參考價值,有興趣的可以了解一下
    2017-09-09
  • 如何利用vue.js實(shí)現(xiàn)拖放功能

    如何利用vue.js實(shí)現(xiàn)拖放功能

    這篇文章主要給大家介紹了如何利用vue.js實(shí)現(xiàn)拖放功能的相關(guān)資料,本文并未使用現(xiàn)有的庫,而是使用內(nèi)置的HTML拖放API來實(shí)現(xiàn)簡單的拖放系統(tǒng),需要的朋友可以參考下
    2021-06-06
  • Vue?2源碼閱讀?Provide?Inject?依賴注入詳解

    Vue?2源碼閱讀?Provide?Inject?依賴注入詳解

    這篇文章主要為大家介紹了Vue?2源碼閱讀?Provide?Inject?依賴注入詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08

最新評論

上虞市| 丹凤县| 缙云县| 河间市| 太仓市| 九龙坡区| 高尔夫| 丹寨县| 大兴区| 古蔺县| 青冈县| 镇远县| 长丰县| 汝州市| 精河县| 钦州市| 图木舒克市| 平潭县| 宜阳县| 遂昌县| 房产| 永吉县| 安义县| 文成县| 钦州市| 怀安县| 昌江| 龙陵县| 阿巴嘎旗| 历史| 台东县| 苍溪县| 罗源县| 沙坪坝区| 远安县| 柘荣县| 内乡县| 客服| 惠东县| 托克托县| 斗六市|