就是很普通的树形结构,所存在的问题就是,返回的数据中,子集可能有几条几万条不等,存在的问题也显而易见了
数据量过大,样式越复杂,浏览器舒渲染的过程就会越慢。
html
// 这里我使用的是render-content方式生成tree组件样式
<div class="cont" ref="list" @scroll="handleScroll($event)">
<el-tree
class="filter-tree"
:style="{ transform: getTransform, height: listHeight + 'px' }"
ref="tree"
accordion
:data="newList"
:props="defaultProps"
:default-expand-all="false"
:filter-node-method="filterNode"
:render-content="renderContent"
:expand-on-click-node="false"
:render-after-expand="false"
:check-on-click-node="true"
@node-click="handleNodeClick"
@node-expand="handleOpen"
@node-collapse="handleClose"
></el-tree>
</div>
js,首先将原数据存在vuex中
1.绑定scroll,让可视区域编程虚拟列表,实时替换子集
思路
- 计算出可视区域和滑动后的索引位置
- 与原数组对比,实时更新新数组
- 计算偏移量,让用户可以一直滚动
<script>
export default {
name: 'TreeFunction',
props: {
treeList: {
type: Array,
required: true,
default: () => []
},
tabTopTypeApprove: {
type: String,
required: false,
default: 'plan'
}
},
data () {
return {
defaultProps: {
children: 'children',
label: 'label'
},
screenHeight: 0, // 可视区域高度
startOffset: 0, // 偏移量
start: 0, // 起始索引
end: null, // 结束索引
itemSize: 24, // 每项高度
treeAllList: 0,
newList: [],
terrClickKey: ''
}
},
watch: {
// 因为是组件,这边监听传入的值第一次初始化
dataList: {
handler: function (val, oldVal) {
// eslint-disable-next-line prefer-const
let treeStandardList = JSON.parse(
JSON.stringify(this.$store.state.user.treeStandardList)
)
treeStandardList.forEach((_) => {
if (_.children && _.children.length > 20) {
_.children = _.children.slice(0, 12)
}
})
this.newList = treeStandardList
},
deep: true
}
},
computed: {
dataList () {
return this.treeList
},
visibleCount () {
const clientHeight = this.$el.clientHeight - 36 // 当前容器可视区域
return Math.ceil(clientHeight / this.itemSize)
}, // 当前列表可显示多少条
// 偏移量对应的style
getTransform () {
return `translate3d(0,${this.startOffset}px,0)`
},
listHeight () {
// 我的默认高度是277
return !this.treeAllList ? 277 : this.treeAllList
}
},
mounted () {},
created () {},
methods: {
renderContent (h, { node, data, store }) {
// TO DO
// 这个太长了,就...
},
handleOpen (data, node) {
this.terrClickKey = data.label
},
handleScroll (e) {
const scrollTop = this.$refs.list.scrollTop // 当前滚动条
this.start = Math.floor(scrollTop / this.itemSize) // 索引开始位置
this.end = this.start + this.visibleCount
// eslint-disable-next-line prefer-const
let treeStandardList = JSON.parse(
JSON.stringify(this.$store.state.user.treeStandardList)
)
// eslint-disable-next-line no-unused-vars
let list = []
// eslint-disable-next-line no-unused-vars
let allHeight = 0
// 找到原始数组,找出对应下标的数组
treeStandardList.forEach((_) => {
if (this.terrClickKey === _.label) {
allHeight = _.children.length * this.itemSize
if (!allHeight) {
return false
} else {
list = _.children.slice(
this.start,
Math.min(this.end, _.children.length)
)
}
}
})
// 找到现在使用的数组进行进行替换(这边没有返回唯一key或者id之类的东西,我只能用名称对比了)
this.newList.forEach((_) => {
if (this.terrClickKey === _.label) {
_.children = list
}
})
this.treeAllList = allHeight // 设置高度
this.startOffset =
scrollTop > allHeight
? allHeight
: scrollTop
? scrollTop - ((scrollTop % this.itemSize) + 24)
: 0 // 此时的偏移量 加了24px是因为父级高度会在最上方
}
}
}
</script>
后面再说两种思路吧
2.同样使用虚拟列表的方式,只是采用的向数组添加和移除无用的数据
3.自己模拟个翻页功能