11import 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 ;
0 commit comments