参考了 大佬的文章https://zhuanlan.zhihu.com/p/...
模仿着自己实现了一个长列表可视区域渲染功能 代码如下(基本和原文一致)
滚动组件
<template>
<div class="list-view" @scroll="handleScroll($event)">
<div
class="list-view-phantom"
:style="{ height: data.length * 30 + 'px' }"
></div>
<div ref="content" class="list-view-content">
<div class="list-view-item" v-for="item in visibleData" :key="item.value">
值:{{ item.value }}
</div>
</div>
</div>
</template>
<script>
export default {
props: {
data: {
type: Array
},
itemHeight: {
type: Number,
default: 30
}
},
mounted() {
this.$nextTick(() => {
this.visibleCount = Math.ceil(
this.$el.clientHeight / this.itemHeight
);//获取可视区域可渲染个数
this.start = 0;
this.end = this.start + this.visibleCount;
this.visibleData = this.data.slice(this.start, this.end);
});
},
data() {
return {
start: 0,
end: 0,
visibleCount: 0,
visibleData: [],
scrollTop: 0
};
},
methods: {
handleScroll(event) {
const scrollTop = this.$el.scrollTop;//获取 dom 滚动高度
const offsetNumber = Math.floor(scrollTop / this.itemHeight); //计算偏移个数
const fixedScrollTop = offsetNumber * this.itemHeight; //计算偏移高度
this.$refs.content.style.webkitTransform = `translateY(${fixedScrollTop}px)`; //设置属性
//计算开始 结束 数据
this.start = offsetNumber;
this.end = this.start + this.visibleCount;
this.visibleData = this.data.slice(this.start, this.end);
}
}
};
</script>
<style lang="scss" scoped>
.list-view {
height: 400px;
overflow: auto;
position: relative;
border: 1px solid #666;
.list-view-content {
left: 0;
right: 0;
top: 0;
position: absolute;
}
.list-view-item {
color: #666;
min-height: 30px;
line-height: 30px;
box-sizing: border-box;
}
?.list-view-phantom {
position: absolute;
height: 30px;
left: 0;
top: 0;
right: 0;
z-index: -1;
}
}
</style>
代码 赋值就能用,父组件传递一个 data 就行了
父组件
<template>
<div class="home">
<Scroll :data="items" />
</div>
</template>
<script>
// @ is an alias to /src
import Scroll from "./scroll";
export default {
name: "Home",
components: {
Scroll
},
data() {
return {
items: []
};
},
mounted() {
for (let i = 0; i < 10000; i++) {
this.items.push({ value: i });
}
}
};
</script>
这个效果非常棒~~
现在遇到一个需求,做出如下修改
在.list-view-item dom 结构中新增一个子元素 点击父元素的时候会展示子元素 (子元素高度不确定 可能有很多内容)
代码如下
<template>
<div class="list-view" @scroll="handleScroll($event)">
<div
class="list-view-phantom"
:style="{ height: data.length * 30 + 'px' }"
></div>
<div ref="content" class="list-view-content">
<div class="list-view-item" v-for="(item,index) in visibleData" :key="item.value">
<div @click="check(item)">父元素值:{{ item.value }}</div>
<div style="min-height:100px" v-if="checkedValue===item.value">
我是子元素{{item.value+1}}
</div>
</div>
</div>
</div>
</template>
? ?
<script>
export default {
props: {
data: {
type: Array
},
itemHeight: {
type: Number,
default: 30
}
},
mounted() {
this.$nextTick(() => {
this.visibleCount = Math.ceil(
this.$el.clientHeight / this.itemHeight
);//获取可视区域可渲染个数
this.start = 0;
this.end = this.start + this.visibleCount;
this.visibleData = this.data.slice(this.start, this.end);
});
},
data() {
return {
checkedValue:-1,
start: 0,
end: 0,
visibleCount: 0,
visibleData: [],
scrollTop: 0
};
},
methods: {
check(item){
if(this.checkedValue===item.value) return this.checkedValue=-1
this.checkedValue=item.value
},
handleScroll(event) {
const scrollTop = this.$el.scrollTop;//获取 dom 滚动高度
const offsetNumber = Math.floor(scrollTop / this.itemHeight); //计算偏移个数
const fixedScrollTop = offsetNumber * this.itemHeight; //计算偏移高度
this.$refs.content.style.webkitTransform = `translateY(${fixedScrollTop}px)`; //设置属性
//计算开始 结束 数据
this.start = offsetNumber;
this.end = this.start + this.visibleCount;
this.visibleData = this.data.slice(this.start, this.end);
}
}
};
</script>
<style lang="scss" scoped>
.list-view {
height: 400px;
overflow: auto;
position: relative;
border: 1px solid #666;
.list-view-content {
left: 0;
right: 0;
top: 0;
position: absolute;
}
.list-view-item {
color: #666;
min-height: 30px;
line-height: 30px;
box-sizing: border-box;
}
?.list-view-phantom {
position: absolute;
height: 30px;
left: 0;
top: 0;
right: 0;
z-index: -1;
}
}
</style>
这个时候滚动就会产生bug 开始跳跃,研究了一天了还是没有解决...
自己的思路就是获取第一个 渲染的 dom 父子元素的总高度, 然后计算偏移量的时候 itemHeight = dom 父子元素总高度,但是 滚动到下一个的时候会发现 scrollTop 过大导致直接偏移不准确
求大佬 求思路~