Skip to content

Commit 2746893

Browse files
committed
Change flip way.
1 parent adbdd86 commit 2746893

File tree

7 files changed

+54
-188
lines changed

7 files changed

+54
-188
lines changed

demo/demo.vue

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,24 @@
11
<template>
22
<div>
3-
<virtual-list
4-
:unit="30"
5-
:remain="10"
6-
:amount="20"
3+
<VirtualList
4+
:itemHeight="30"
5+
:remainItems="10"
76
v-on:toBottom="onBottom"
87
>
9-
<Item v-for="item in items" :item="item" :key="item.id" />
10-
</virtual-list>
11-
12-
<!-- <Item v-for="item in items" :item="item" :key="item.id" /> -->
8+
<Item v-for="item in items" :item="item" :key="$index" />
9+
</VirtualList>
1310
</div>
1411
</template>
1512

1613
<script>
17-
import 'virtual-list';
1814
import Item from './item.vue';
15+
import VirtualList from 'virtual-list';
1916
import { fetchData } from './request_mock';
2017
2118
export default {
2219
name: 'apptest',
2320
24-
components: { Item },
21+
components: { Item, VirtualList },
2522
2623
watch: {
2724
items (list) {
@@ -37,7 +34,7 @@
3734
3835
methods: {
3936
onBottom () {
40-
// let list = fetchData();
37+
// let list = fetchData(20);
4138
// if (list.length) {
4239
// this.items = this.items.concat(list);
4340
// }

demo/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!DOCTYPE html>
2-
<html>
2+
<html lang="en-US">
33
<head>
44
<meta charset="utf-8">
55
<title>Vue virtual scroll list</title>

demo/index.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import Vue from 'vue';
22
import Demo from './demo.vue';
33

4-
Vue.use(Demo);
5-
64
new Vue({
75
el: '#app',
86
template: '<Demo />',

demo/item.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
.list-item {
2121
height: 30px;
2222
line-height: 30px;
23+
border-bottom: 1px solid #eee;
2324
}
2425
/*.list-item:nth-child(2n) {
2526
background: #efefef;

demo/request_mock.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Mock from 'mockjs';
22

3-
let user_count = 1;
3+
let user_count = 0;
44
let request_times = 0;
55
export function fetchData (count = 20, times) {
66
var list = [];

src/index.js

Lines changed: 43 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -1,187 +1,88 @@
11
import Vue from 'vue';
2-
import { throttle } from './util';
32

4-
Vue.component('virtual-list', {
3+
const VirtualList = Vue.component('vue-virtual-scroll-list', {
54

65
props: {
7-
unit: {
6+
itemHeight: {
87
type: Number,
98
required: true
109
},
11-
remain: {
12-
type: Number,
13-
required: true
14-
},
15-
amount: {
10+
remainItems: {
1611
type: Number,
1712
required: true
1813
}
1914
},
2015

2116
// an object helping to calculate
2217
delta: {
23-
// scroll
24-
direct: '',
25-
last_top: 0,
26-
page_type: '',
27-
// data
28-
total: 0,
29-
joints: 0,
30-
start_index: 0,
31-
// style
32-
view_height: 0,
33-
all_padding: 0,
34-
padding_top: 0,
35-
bench_padding: 0
18+
start: 0, // start index
19+
end: 0, // end index
20+
keeps: 0, // nums of item keeping in real dom
21+
total: 0, // all items count
22+
viewHeight: 0, // viewport height
23+
allPadding: 0, // all padding of not-render-yet doms
24+
paddingTop: 0 // container real padding-top
3625
},
3726

3827
methods: {
39-
onScroll: throttle(function () {
40-
let delta = this.$options.delta;
41-
let scrollTop = this.$refs.container.scrollTop;
42-
let listHeight = this.$refs.listbox.offsetHeight;
43-
44-
this.saveDirect(scrollTop);
45-
46-
// scroll to top
47-
if (scrollTop === 0) {
48-
this.$emit('toTop');
49-
}
50-
51-
// scroll to bottom
52-
let paddingBottom = delta.all_padding - delta.padding_top;
53-
if (listHeight <= scrollTop + delta.view_height + paddingBottom) {
54-
this.showNext();
55-
}
56-
57-
if (delta.direct === 'UP' && scrollTop < delta.padding_top) {
58-
this.showPrev();
59-
}
60-
}, 10, true, true),
61-
62-
saveDirect (scrollTop) {
63-
let delta = this.$options.delta;
64-
65-
if (!delta.last_top) {
66-
delta.last_top = scrollTop;
67-
} else {
68-
delta.direct = delta.last_top > scrollTop ? 'UP' : 'DOWN';
69-
delta.last_top = scrollTop;
70-
}
28+
onScroll () {
29+
this.updateZone(this.$refs.container.scrollTop);
7130
},
7231

73-
showNext () {
32+
updateZone (offset) {
7433
let delta = this.$options.delta;
34+
let overs = Math.floor(offset / this.itemHeight);
7535

76-
delta.page_type = 'NEXT';
77-
if (delta.total - delta.start_index <= this.amount) {
78-
this.$emit('toBottom');
79-
} else {
80-
delta.start_index = delta.start_index + this.amount;
81-
this.$forceUpdate();
36+
// need moving items at lease one unit height
37+
// @todo: consider prolong the zone range size
38+
let start = overs ? overs : 0;
39+
let end = overs ? (overs + delta.keeps) : delta.keeps;
40+
41+
if (overs + this.remainItems >= delta.total) {
42+
end = delta.total;
43+
start = delta.total - delta.keeps;
8244
}
83-
},
8445

85-
showPrev () {
86-
this.$options.delta.page_type = 'PREV';
46+
delta.end = end;
47+
delta.start = start;
48+
49+
// call component to update items
8750
this.$forceUpdate();
88-
this.$emit('toPrev');
8951
},
9052

9153
filter (items) {
92-
let length = items.length;
9354
let delta = this.$options.delta;
94-
let nowStartIndex, udf, list = [];
95-
96-
if (!delta.total) {
97-
delta.total = length;
98-
}
99-
100-
if (delta.page_type === 'PREV') {
101-
// already the first page
102-
if (delta.start_index === 0) {
103-
list = items.filter((item, index) => {
104-
return index >= 0 && index < this.amount;
105-
});
106-
} else {
107-
list = items.filter((item, index) => {
108-
if (index === delta.start_index - this.amount) {
109-
nowStartIndex = index;
110-
}
111-
112-
return index >= (delta.start_index - this.amount)
113-
&& index < delta.start_index;
114-
});
115-
116-
if (nowStartIndex !== udf) {
117-
delta.start_index = nowStartIndex;
118-
}
119-
}
120-
121-
delta.padding_top = delta.start_index * this.unit;
122-
} else {
123-
// flipping next or first render
124-
125-
// virtual list has no any increase
126-
// just flip to next page from start index
127-
if (length === delta.total) {
128-
list = items.filter((item, index) => {
129-
return index >= delta.start_index
130-
&& index < delta.start_index + this.amount;
131-
});
132-
} else {
133-
list = items.filter((item, index) => {
134-
if (index === delta.start_index + this.amount) {
135-
nowStartIndex = index;
136-
}
137-
138-
return index >= (delta.start_index + this.amount)
139-
&& index < (delta.start_index + this.amount * 2);
140-
});
141-
142-
if (nowStartIndex !== udf) {
143-
delta.start_index = nowStartIndex;
144-
}
145-
146-
// save virtual list new length
147-
delta.total = length;
148-
}
14955

150-
// all padding pixel, include top and bottom
151-
// except amount and calculate when component update
152-
delta.all_padding = (length - this.amount) * this.unit;
153-
// padding-top piexl
154-
delta.padding_top = delta.start_index * this.unit;
155-
}
56+
delta.total = items.length;
57+
delta.paddingTop = this.itemHeight * delta.start;
58+
delta.allPadding = this.itemHeight * (items.length - delta.keeps);
15659

157-
return list;
60+
return items.filter((item, index) => {
61+
return index >= delta.start && index <= delta.end;
62+
});
15863
}
15964
},
16065

16166
beforeMount () {
67+
let remains = this.remainItems;
16268
let delta = this.$options.delta;
163-
delta.joints = Math.ceil(this.remain / 2);
164-
delta.view_height = this.remain * this.unit;
165-
delta.bench_padding = delta.joints * this.unit;
166-
},
69+
let bench = Math.ceil(remains / 2);
16770

168-
updated () {
169-
window.requestAnimationFrame(() => {
170-
let delta = this.$options.delta;
171-
this.$refs.container.scrollTop = delta.padding_top + delta.bench_padding;
172-
});
71+
delta.end = remains + bench;
72+
delta.keeps = remains + bench;
73+
delta.viewHeight = this.itemHeight * remains;
17374
},
17475

17576
render (createElement) {
176-
let delta = this.$options.delta;
17777
let showList = this.filter(this.$slots.default);
78+
let { viewHeight, paddingTop, allPadding } = this.$options.delta;
17879

17980
return createElement('div', {
18081
'ref': 'container',
18182
'class': 'virtual-list',
18283
'style': {
18384
'overflow-y': 'auto',
184-
'height': delta.view_height + 'px'
85+
'height': viewHeight + 'px'
18586
},
18687
'on': {
18788
'scroll': this.onScroll
@@ -194,11 +95,13 @@ Vue.component('virtual-list', {
19495
createElement('div', {
19596
'class': 'virtual-list-box-padding',
19697
'style': {
197-
'padding-top': delta.padding_top + 'px',
198-
'padding-bottom': (delta.all_padding - delta.padding_top) + 'px'
98+
'padding-top': paddingTop + 'px',
99+
'padding-bottom': (allPadding - paddingTop) + 'px'
199100
}
200101
}, showList)
201102
])
202103
]);
203104
}
204105
});
106+
107+
export default VirtualList;

src/util.js

Lines changed: 0 additions & 33 deletions
This file was deleted.

0 commit comments

Comments
 (0)