Skip to content

Commit e2ef65a

Browse files
committed
Use delta as a private object avoid mix next request.
1 parent 06fef3d commit e2ef65a

File tree

2 files changed

+71
-46
lines changed

2 files changed

+71
-46
lines changed

demo/demo.vue

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<virtual-list
44
:unit="30"
55
:remain="10"
6-
:pageCounts="20"
6+
:amount="20"
77
v-on:bottom="onBottom"
88
>
99
<Item v-for="item in items" :item="item" :key="item.id" />
@@ -21,6 +21,12 @@
2121
2222
components: { Item },
2323
24+
watch: {
25+
items (list) {
26+
document.title = `Totoal: ${list.length}, Padding: ${(list.length - 10) * 30}`;
27+
}
28+
},
29+
2430
data () {
2531
return {
2632
items: fetchData()

src/index.js

Lines changed: 64 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,6 @@
11
import Vue from 'vue';
22
import { throttle } from './util';
33

4-
// some data help to calculate
5-
let delta = {
6-
// about scroll
7-
direct: '',
8-
last_top: 0,
9-
page_type: '',
10-
11-
// about data
12-
total: 0,
13-
joints: 0,
14-
start_index: 0,
15-
16-
// about style
17-
view_height: 0,
18-
all_padding: 0,
19-
padding_top: 0,
20-
bench_padding: 0
21-
};
22-
23-
// save scroll direct and last scroll position
24-
const saveDirect = (scrollTop) => {
25-
if (!delta.last_top) {
26-
delta.last_top = scrollTop;
27-
} else {
28-
delta.direct = delta.last_top > scrollTop ? 'UP' : 'DOWN';
29-
delta.last_top = scrollTop;
30-
}
31-
};
32-
334
Vue.component('virtual-list', {
345

356
props: {
@@ -41,18 +12,36 @@ Vue.component('virtual-list', {
4112
type: Number,
4213
required: true
4314
},
44-
pageCounts: {
15+
amount: {
4516
type: Number,
4617
required: true
4718
}
4819
},
4920

21+
// an object helping to calculate
22+
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
36+
},
37+
5038
methods: {
5139
onScroll: throttle(function () {
40+
let delta = this.$options.delta;
5241
let scrollTop = this.$refs.container.scrollTop;
5342
let listHeight = this.$refs.listbox.offsetHeight;
5443

55-
saveDirect(scrollTop);
44+
this.saveDirect(scrollTop);
5645

5746
// scroll to top
5847
if (scrollTop === 0) {
@@ -70,19 +59,38 @@ Vue.component('virtual-list', {
7059
}
7160
}, 16, true, true),
7261

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+
}
71+
},
72+
7373
showNext () {
74+
let delta = this.$options.delta;
75+
7476
delta.page_type = 'NEXT';
75-
this.$emit('bottom');
77+
if (delta.total - delta.start_index <= this.amount) {
78+
this.$emit('bottom');
79+
} else {
80+
delta.start_index = delta.start_index + this.amount;
81+
this.$forceUpdate();
82+
}
7683
},
7784

7885
showPrev () {
79-
delta.page_type = 'PREV';
86+
this.$options.delta.page_type = 'PREV';
8087
this.$forceUpdate();
8188
this.$emit('prev');
8289
},
8390

8491
filter (items) {
8592
let length = items.length;
93+
let delta = this.$options.delta;
8694
let nowStartIndex, udf, list = [];
8795

8896
if (!delta.total) {
@@ -92,14 +100,14 @@ Vue.component('virtual-list', {
92100
if (delta.page_type === 'PREV') {
93101
// already the first page
94102
if (delta.start_index === 0) {
95-
list = items.slice(0, this.pageCounts);
103+
list = items.slice(0, this.amount);
96104
} else {
97105
list = items.filter((item, index) => {
98-
if (index === delta.start_index - this.pageCounts) {
106+
if (index === delta.start_index - this.amount) {
99107
nowStartIndex = index;
100108
}
101109

102-
return index >= (delta.start_index - this.pageCounts)
110+
return index >= (delta.start_index - this.amount)
103111
&& index < delta.start_index;
104112
});
105113

@@ -110,54 +118,65 @@ Vue.component('virtual-list', {
110118
delta.padding_top = delta.start_index * this.unit;
111119
}
112120
} else {
121+
// flipping next or first render
122+
113123
// virtual list has no any increase
124+
// just flip to next page from start index
114125
if (length === delta.total) {
115-
list = items;
126+
list = items.filter((item, index) => {
127+
return index >= delta.start_index
128+
&& index < delta.start_index + this.amount;
129+
});
116130
} else {
117131
list = items.filter((item, index) => {
118-
if (index === delta.start_index + this.pageCounts) {
132+
if (index === delta.start_index + this.amount) {
119133
nowStartIndex = index;
120134
}
121135

122-
return index >= (delta.start_index + this.pageCounts)
123-
&& index < (delta.start_index + this.pageCounts * 2);
136+
return index >= (delta.start_index + this.amount)
137+
&& index < (delta.start_index + this.amount * 2);
124138
});
125139

126140
if (nowStartIndex !== udf) {
127141
delta.start_index = nowStartIndex;
128142
}
129143

130-
// item counts of all virtual list
144+
// save virtual list new length
131145
delta.total = length;
132-
// all padding pixel, except remain in viewport items
146+
// all padding pixel, include top and bottom
147+
// except remain and calculate when component update
133148
delta.all_padding = (length - this.remain) * this.unit;
134-
// padding-top piexl
135-
delta.padding_top = delta.start_index * this.unit;
136149
}
150+
151+
// padding-top piexl
152+
delta.padding_top = delta.start_index * this.unit;
137153
}
138154

139155
return list;
140156
}
141157
},
142158

143159
beforeMount () {
144-
delta.view_height = this.remain * this.unit;
160+
this.$options.delta.view_height = this.remain * this.unit;
145161
},
146162

147163
mounted () {
164+
let delta = this.$options.delta;
148165
delta.joints = Math.ceil(this.remain / 2);
149166
delta.bench_padding = delta.joints * this.unit;
150167
},
151168

152169
beforeUpdate () {},
153170

154171
updated () {
172+
let delta = this.$options.delta;
155173
window.requestAnimationFrame(() => {
156174
this.$refs.container.scrollTop = delta.padding_top + delta.bench_padding;
157175
});
158176
},
159177

160178
render (createElement) {
179+
let delta = this.$options.delta;
161180
let slots = this.$slots.default;
162181
let showList = this.filter(slots);
163182

0 commit comments

Comments
 (0)