Vue.js Infinite scrolling RxJS
▌Introduction
We will implement an infinite
scrolling page in vue.js and RxJS.
▌Environment
▋vue.js 2.5.13
▋RxJS 5.5.6
▌Implement
▋What we should do
1. Backend data (Of course! But I will skip this part.)
2. Observe the scroll down event and when the bottom is touched, get the new
data to display.
3. Current (or next) displayed data range, such as “first” and “last” flags,
which are the parameters for getting new data in 2.
▋Observe the scroll event
let observable$ =
Rx.Observable.fromEvent(window, 'scroll').map(x => x);
let subscription$ = observable$
.map(x => Rx.Observable.of(x).delay(500))
.switch()
.subscribe(ev => {
if
((window.innerHeight + window.pageYOffset) >= document.body.offsetHeight) {
//TODO: When
scroll to bottom, get the new data
}
});
}
Use map, delay and switch
to observe the window.onscroll and subscribe a receiving-new-data action if a
user scrolls to bottom.
You can use the following codes to bind a callback
on window.onscroll without RxJS.
window.onscroll = function (ev) {
if
((window.innerHeight + window.pageYOffset) >= document.body.offsetHeight) {
//console.log('Already
scroll to bottom!');
}
};
▋Current range of data
Let’s create
1. A constant variable to store the default “first” and “last” and “max”.
Notice that “max” is the maximal number of data every time we get from backend.
Notice that “max” is the maximal number of data every time we get from backend.
2. Current/Next “first” and “last”
For example, default (first, last)=(1,100), while
max = 100, the next range will be (101,200).
const constRowLimit = { first: 1, last: 1000, max: 1000 };
rowLimit: { first: constRowLimit.first, last:
constRowLimit.last, isLast: false }
▋Receiving new data
Last step, use the above variable rowLimit,
to get the data from backend. In this example, I use OData to get them with Id located between rowLimit.first
and rowLimit.last.
_renderData = function () {
getUri =
serverUri.concat("?$filter=Id ge ", rowLimit.first,
" and Id le ", rowLimit.last);
//Set next
range
rowLimit.first
+= constRowLimit.max;
rowLimit.last
+= constRowLimit.max;
axios.get(getUri)
.then(function (response) {
//Append response.data to our model
});
},
▋Full sample codes
▋JS
const constRowLimit = { first: 1, last: 1000, max: 1000 };
var app = new Vue({
el: '#app',
data: {
books: [],
rowLimit: {
first: constRowLimit.first, last: constRowLimit.last, isLast: false }
},
methods: {
_renderData:
function () {
var vm = this;
let
isFirstRender = true;
if
(vm.rowLimit.first !== constRowLimit.first)
isFirstRender
= false;
getUri =
vm.$serverUri.concat("?$filter=Id ge ",
vm.rowLimit.first, " and Id le ",
vm.rowLimit.last);
//Set next
range
vm.rowLimit.first
+= constRowLimit.max;
vm.rowLimit.last
+= constRowLimit.max;
//判斷是否已無資料
if (vm.rowLimit.isLast
=== true)
return;
axios.get(getUri)
.then(function (response) {
if
(!response.data || response.data.length === 0) {
vm.rowLimit.isLast = true;
}
else {
response.data.forEach(x => {
vm.books.push(x);
});
}
});
},
//When
scroll to bottom, get the new data
_observeScollToBottom: function () {
var vm = this;
let observable$ =
Rx.Observable.fromEvent(window, 'scroll').map(x => x);
let
subscription$ = observable$
.map(x => Rx.Observable.of(x).delay(500))
.switch()
.subscribe(ev => {
if
((window.innerHeight + window.pageYOffset) >= document.body.offsetHeight) {
vm._renderDictionaries(vm.keyword, vm.rowLimit.first, vm.rowLimit.last);
}
});
},
mounted: function () {
var vm = this;
vm._observeScollToBottom();
vm._renderDictionaries();
}
})
▋HTML
<any v-for="bok in
books">
</any>
▋Demo
▌Reference
沒有留言:
張貼留言