您好,登錄后才能下訂單哦!
今天小編給大家分享一下基于Vue如何封裝一個虛擬列表組件的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
使用方法
<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>
參數 | 說明 | 類型 | 可選值 | 默認值 |
---|---|---|---|---|
allData | 全部數據 | Array | - | [] |
virtualData | 虛擬數據 | Array | - | [] |
itemHeight | 每行的高度,用于計算滾動距離 | Number, String | - | 30 |
插槽名 | 說明 |
---|---|
- | 自定義默認內容,即主體區域 |
首先梳理我想要的組件效果:
滾動條正常顯示
加載渲染大量數據不卡頓
能對列表數據進行操作增刪等
需要把顯示框分為3部分:顯示高度,全部高度,虛擬數據高度
大概的比例是這樣的
為達到滾動條的效果,在最外層顯示高度設置overflow: auto
可以把滾動條撐出來,全部高度則設置position: absolute;z-index: -1;height: auto;
,虛擬數據高度則設置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" :/> <!-- 存放顯示數據 --> <div class="virtual-list" :/> </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>
如果想要渲染不卡頓,就得只加載顯示區域的虛擬數據,虛擬數據的更新邏輯為:用startIndex
和endIndex
標志虛擬數據的起始索引和結束索引,在滾動條滑動時,通過計算滑動的距離去更新startIndex
和endIndex
。另外用offset
標記偏移量,對虛擬數據區域設置transform: translate3d(0, ${this.offset}px, 0)
跟著滾動條去移動
核心部分代碼如下
scrollEvent(e) { const scrollTop = this.$refs.virtualList.scrollTop // 起始索引 = 滾動距離 / 每項高度 this.startIndex = Math.floor(scrollTop / this.itemHeight) // 結束索引 = 開始索引 + 可見數量 this.endIndex = this.startIndex + this.visibleCount // 偏移量 = 滾動距離 this.offset = scrollTop - (scrollTop % this.itemHeight) }
如果想要在數據里添加操作按鈕,則需要在封裝組件時設置插槽,且需要把虛擬數據同步給父組件
設置插槽
<!-- 顯示高度 --> <div ref="virtualList" class="hub-virtual-list-show-height" @scroll="scrollEvent($event)"> <!-- 全部高度,撐出滾動條 --> <div class="hub-virtual-list-all-height" :/> <!-- 存放顯示數據 --> <div class="virtual-list" :> <!-- 設置插槽 --> <slot/> </div> </div>
滾動時把虛擬數據同步給父組件
scrollEvent(e) { const scrollTop = this.$refs.virtualList.scrollTop // 起始索引 = 滾動距離 / 每項高度 this.startIndex = Math.floor(scrollTop / this.itemHeight) // 結束索引 = 開始索引 + 可見數量 this.endIndex = this.startIndex + this.visibleCount // 偏移量 = 滾動距離 this.offset = scrollTop - (scrollTop % this.itemHeight) // 同步父組件數據 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" :/> <!-- 存放顯示數據 --> <div class="virtual-list" > <slot/> </div> </div> </div> </template> <script> export default { name: 'hub-virtual-list', props: { // 全部數據 allData: { type: Array, default: () => [] }, // 虛擬數據 virtualData: { type: Array, default: () => [] }, // 每項高度 itemHeight: { type: [Number, String], default: '30' }, // 每項樣式 itemStyle: { type: Object, default: () => {} } }, data() { return { // 起始索引 startIndex: 0, // 結束索引 endIndex: null, // 偏移量,計算滾動條 offset: 0, inVirtualData: [] } }, computed: { // 所有高度 allHeight() { // 每項高度 * 項數 return this.itemHeight * this.allData.length }, // 可見數量 visibleCount() { // 可見高度 / 每項高度 return Math.ceil(this.showHeight / this.itemHeight) }, // 顯示數據的偏移量 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 // 起始索引 = 滾動距離 / 每項高度 this.startIndex = Math.floor(scrollTop / this.itemHeight) // 結束索引 = 開始索引 + 可見數量 this.endIndex = this.startIndex + this.visibleCount // 偏移量 = 滾動距離 this.offset = scrollTop - (scrollTop % this.itemHeight) // 同步父組件數據 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>
以上就是“基于Vue如何封裝一個虛擬列表組件”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。