Skip to content

Commit 2440e25

Browse files
committed
feat: support 'debounce' and 'data-height' option
1 parent d86b243 commit 2440e25

File tree

6 files changed

+412
-213
lines changed

6 files changed

+412
-213
lines changed

README.md

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,18 @@ $ npm install vue-scroll-list --save-dev
2626
<h3>random height</h3>
2727
<h4>total: {{count}}</h4>
2828
<div class="wrapper">
29-
<scroll-list :heights="heightList"
29+
<scroll-list :debounce="50"
3030
:remain="10"
31+
:enabled="true"
32+
:keep="true"
3133
@toTop="onTop"
3234
@toBottom="onBottom"
3335
@scrolling="onScroll">
3436
<div v-for="(item, index) in list"
3537
:key="item.index"
36-
:class="{item: 1}"
37-
:style="{height: item.itemHeight + 'px', 'line-height': item.itemHeight + 'px'}">
38+
:class="['item']"
39+
:style="{height: item.itemHeight + 'px', 'line-height': item.itemHeight + 'px'}"
40+
v-bind="{'data-height': item.itemHeight}">
3841
index:{{item.index}} / height:{{item.itemHeight}}
3942
</div>
4043
</scroll-list>
@@ -76,7 +79,7 @@ $ npm install vue-scroll-list --save-dev
7679
index: i,
7780
itemHeight: itemHeight
7881
});
79-
this.heightList.push(itemHeight);
82+
// this.heightList.push(itemHeight);
8083
}
8184
console.log('[demo]:' + size + ' items are created.')
8285
}
@@ -124,7 +127,7 @@ Available `Prop` :
124127

125128
*Prop* | *Type* | *Required* | *Description* |
126129
:--- | :--- | :--- | :--- |
127-
| heights | Array | | A array contains all height of your item. |
130+
| heights | Array | * | An array contains all height of your item.If you want to use `data-height`,please ignore this option. |
128131
| remain | Number | * | The number of item that show in view port.(default `10`) |
129132
| keep | Boolean | * | Work with `keep-alive` component,keep scroll position after activated.(default `false`) |
130133
| enabled | Boolean | * | If you want to render all data directly,please set 'false' for this option.But `toTop``toBottom` and `scrolling` event is still available.(default `true`) |
@@ -137,6 +140,37 @@ Available `Event` :
137140
| toBottom | An event emit by this library when this list is scrolled on bottom. |
138141
| scrolling | An event emit by this library when this list is scrolling. |
139142

143+
## About heights prop
144+
`heights` property is an array contains all height of your item,but you can tell us then height of each item by setting the `data-height` property.
145+
```html
146+
<div v-for="item in list"
147+
:key="item.index"
148+
v-bind="{'data-height': item.itemHeight}">
149+
</div>
150+
```
151+
Sometimes you may need to change your the height of each item or filter your item.This may cause some blank problems.So you'd better call `update` function to tell us.
152+
```html
153+
<scroll-list
154+
ref="vueScrollList"
155+
:debounce="50"
156+
:remain="10"
157+
:enabled="true"
158+
:keep="true"
159+
@toTop="onTop"
160+
@toBottom="onBottom"
161+
@scrolling="onScroll">
162+
<div v-for="item in list"
163+
:key="item.index"
164+
:class="['item']"
165+
:style="{height: item.itemHeight + 'px', 'line-height': item.itemHeight + 'px'}"
166+
v-bind="{'data-height': item.itemHeight}">
167+
index:{{item.index}} / height:{{item.itemHeight}}
168+
</div>
169+
</scroll-list>
170+
```
171+
```js
172+
this.$refs.vueScrollList && this.$refs.vueScrollList.update();
173+
```
140174
## License
141175

142176
[MIT License](https://github.com/KyLeoHC/vue-scroll-list/blob/master/LICENSE)

dist/vue-scroll-list.common.js

Lines changed: 91 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,23 @@
11
'use strict';
22

3+
var _debounce = function _debounce(fn, wait) {
4+
var timeoutId = null;
5+
return function () {
6+
var _this = this,
7+
_arguments = arguments;
8+
9+
var laterFn = function laterFn() {
10+
fn.apply(_this, _arguments);
11+
};
12+
clearTimeout(timeoutId);
13+
timeoutId = setTimeout(laterFn, wait);
14+
};
15+
};
16+
317
var component = {
418
props: {
519
heights: {
6-
type: Array,
7-
required: true
20+
type: Array
821
},
922
remain: {
1023
type: Number,
@@ -17,27 +30,29 @@ var component = {
1730
keep: {
1831
type: Boolean,
1932
default: false
33+
},
34+
debounce: {
35+
type: Number
2036
}
2137
},
22-
data: function data() {
23-
return {
24-
scrollTop: 0,
25-
start: 0, // start index
26-
end: 0, // end index
27-
total: 0, // all items count
28-
keeps: 0, // number of item keeping in real dom
29-
paddingTop: 0, // all padding of top dom
30-
paddingBottom: 0, // all padding of bottom dom
31-
reserve: 6 // number of reserve dom for pre-render
32-
};
33-
},
34-
3538
methods: {
3639
handleScroll: function handleScroll(event) {
3740
var scrollTop = this.$el.scrollTop;
38-
this.$emit('scrolling', event);
39-
this.enabled ? this.updateZone(scrollTop) : this.updateZoneNormally(scrollTop);
4041
this.scrollTop = scrollTop;
42+
this.$emit('scrolling', event);
43+
this.updateZone(scrollTop);
44+
},
45+
updateHeightList: function updateHeightList() {
46+
if (this.heights) {
47+
this.heightList = this.heights;
48+
} else {
49+
var list = this.$slots.default || [];
50+
if (list.length !== this.heightList.length) {
51+
this.heightList = list.map(function (vnode) {
52+
return parseInt(vnode.data.attrs['data-height']);
53+
});
54+
}
55+
}
4156
},
4257
updateZoneNormally: function updateZoneNormally(offset) {
4358
// handle the scroll event normally
@@ -52,58 +67,65 @@ var component = {
5267
findOvers: function findOvers(offset) {
5368
// compute overs by comparing offset with the height of each item
5469
// @todo: need to optimize this searching efficiency
70+
var heightList = this.heightList;
5571
var overs = 0;
56-
var length = this.heights.length;
57-
var height = this.heights[0];
72+
var height = heightList[0];
5873
var topReserve = Math.floor(this.reserve / 2);
59-
for (; overs < length; overs++) {
74+
for (var length = heightList.length; overs < length; overs++) {
6075
if (offset >= height) {
61-
height += this.heights[overs + 1];
76+
height += heightList[overs + 1];
6277
} else {
6378
break;
6479
}
6580
}
6681
return overs > topReserve - 1 ? overs - topReserve : 0;
6782
},
6883
updateZone: function updateZone(offset) {
69-
var overs = this.findOvers(offset);
70-
71-
// scroll to top
72-
if (!offset && this.total) {
73-
this.$emit('toTop');
74-
}
84+
if (this.enabled) {
85+
this.updateHeightList();
86+
var overs = this.findOvers(offset);
7587

76-
var start = overs || 0;
77-
var end = start + this.keeps;
78-
var totalHeight = this.heights.reduce(function (a, b) {
79-
return a + b;
80-
});
88+
// scroll to top
89+
if (!offset && this.total) {
90+
this.$emit('toTop');
91+
}
8192

82-
// scroll to bottom
83-
if (offset && offset + this.$el.clientHeight >= totalHeight) {
84-
start = this.total - this.keeps;
85-
end = this.total - 1;
86-
this.$emit('toBottom');
87-
}
93+
var start = overs || 0;
94+
var end = start + this.keeps;
95+
var totalHeight = this.heightList.reduce(function (a, b) {
96+
return a + b;
97+
});
8898

89-
this.start = start;
90-
this.end = end;
99+
// scroll to bottom
100+
if (offset && offset + this.$el.clientHeight >= totalHeight) {
101+
start = this.total - this.keeps;
102+
end = this.total - 1;
103+
this.$emit('toBottom');
104+
}
91105

92-
this.$forceUpdate();
106+
if (this.start !== start || this.end !== end) {
107+
this.start = start;
108+
this.end = end;
109+
this.$forceUpdate();
110+
}
111+
} else {
112+
this.updateZoneNormally(offset);
113+
}
93114
},
94115
filter: function filter(slots) {
95-
var _this = this;
116+
var _this2 = this;
96117

118+
this.updateHeightList();
97119
if (!slots) {
98120
slots = [];
99121
this.start = 0;
100122
}
101123

102124
var slotList = slots.filter(function (slot, index) {
103-
return index >= _this.start && index <= _this.end;
125+
return index >= _this2.start && index <= _this2.end;
104126
});
105-
var topList = this.heights.slice(0, this.start);
106-
var bottomList = this.heights.slice(this.end + 1);
127+
var topList = this.heightList.slice(0, this.start);
128+
var bottomList = this.heightList.slice(this.end + 1);
107129
this.total = slots.length;
108130
// consider that the height of item may change in any case
109131
// so we compute paddingTop and paddingBottom every time
@@ -115,12 +137,32 @@ var component = {
115137
}) : 0;
116138

117139
return slotList;
140+
},
141+
update: function update() {
142+
var _this3 = this;
143+
144+
this.$nextTick(function () {
145+
_this3.updateZone(_this3.scrollTop);
146+
});
118147
}
119148
},
149+
beforeCreate: function beforeCreate() {
150+
// vue won't observe this properties
151+
Object.assign(this, {
152+
heightList: [], // list of each item height
153+
scrollTop: 0, // current scroll position
154+
start: 0, // start index
155+
end: 0, // end index
156+
total: 0, // all items count
157+
keeps: 0, // number of item keeping in real dom
158+
paddingTop: 0, // all padding of top dom
159+
paddingBottom: 0, // all padding of bottom dom
160+
reserve: 10 // number of reserve dom for pre-render
161+
});
162+
},
120163
beforeMount: function beforeMount() {
121164
if (this.enabled) {
122165
var remains = this.remain;
123-
124166
this.start = 0;
125167
this.end = remains + this.reserve - 1;
126168
this.keeps = remains + this.reserve;
@@ -133,18 +175,17 @@ var component = {
133175
},
134176
render: function render(h) {
135177
var showList = this.enabled ? this.filter(this.$slots.default) : this.$slots.default;
178+
var debounce = this.debounce;
136179

137180
return h('div', {
138-
class: {
139-
'scroll-container': 1
140-
},
181+
class: ['scroll-container'],
141182
style: {
142183
'display': 'block',
143184
'overflow-y': 'auto',
144185
'height': '100%'
145186
},
146187
on: { // '&' support passive event
147-
'&scroll': this.handleScroll
188+
'&scroll': debounce ? _debounce(this.handleScroll.bind(this), debounce) : this.handleScroll
148189
}
149190
}, [h('div', {
150191
style: {

0 commit comments

Comments
 (0)