Intersection Observer

Intersection Observer

八月 25, 2019

Intersection Observer for Infinite Scroll in Vue Applications

Infinite scrolling 在現代化網站中是一個非常常用的技巧,當觸發某些條件時而再去loading資料,可以給網站的效能帶來大幅的提升。

然而對於前端工程來說,不是一件簡單的事。第一,需要去監聽並控制 scrolling 的事件、行為與屬性。.

有個比較簡單且原生的方式就是Intersection Observer API ,這個api提供了 asynchronously observe changesintersection元素中或是最高層級的 viewport的位置所佔的比重,說那麼多一定聽不懂,下面就直接用vue開始吧。

The Intersection and observation process

被監聽的目標是一種與跟(root)相對位置的概念,當目標碰到root教會觸發回調函數(callbaock),可以用下面的突來解釋會比較清楚。

root

Create an Intersection Observer

因此我們把app.vue當成我們的 root

1
2
3
4
5
const options = {
root: null, /* uses the page as root */
threshold: 0
};
const observer = new IntersectionObserver(callback, options);

以上為主要的宣告方式

root

可以選擇根的元素

1
2
3
const options = {
root: document.querySelector('#divAsRoot'), /* uses the Div element as root */
};

threshold

可以指定閥值的表示型式

threshold
您可能希望觀察者僅在目標進入視圖中途(50%),完全在視圖中(100%)或第二次進入視圖(0%)時執行回調。閾值是你決定的方式。它默認為0意味著即使一個像素在視圖中,觀察者也將執行回調。值為1.0表示在每個像素都在視圖中之前,回調將不會運行。0.5也是如此。僅當目標位於視圖的一半時才會觸發回調。

What should we build?

Random Users API.來取得資料,當scroll滑到最底觸發我們的目標,然後處發回調函數在一次取的我們要的資料。

Create a Vue project

創建

1
2
3
4
vue create scrolling-demo
cd scrolling-demo
npm install --save axios
npm run serve

建立一個 fetchUsers 的function 在beforeMount之前執行他

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!-- src/App.vue --> 

<script>
import axios from "axios";
export default {
name: "app",
data() {
return {
users: [],
};
},
methods: {
fetchUsers() {
for (var i = 0; i < 5; i++) {
axios.get(`https://randomuser.me/api/`).then(response => {
this.users.push(response.data.results[0]);
console.log(response)
});
}
},
beforeMount() {
this.fetchUsers();
}
}
}
</script>

你會看到下面的情形。

demo

把畫面與api資料用v-for帶出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- src/App.vue --> 
<template>
<div id="app">
<div class="user" :key="user.id.value" v-for="user in users">
<div>
<img class="img" :src="user.picture.large">
</div>
<div>
<p>{{ user.name.first }} {{ user.name.last }}</p>
<ul></ul>
</div>
</div>
<div>
<span ref="target"/>
</div>
</div>
</template>

像這樣
demo

接下來加入我們的loadin目標

1
<div ref="divAsTarget"><h3>Loading ... </h3></div> /* below the user's list */

之後再加入intersection監聽事件,綁訂於上述的taqrget

1
2
3
4
mounted() {
this.observer = new IntersectionObserver(this.callback, options);
this.observer.observe(this.$refs.divAsTarget);
}

最後在回掉函數中檢查是否觸發目標

1
2
3
4
5
6
7
callback(entries, observer) {
entries.forEach(entry => {
if (entry.isIntersecting) {
this.fetchUsers();
}
});
}

最後的demo
demo

最後

我把程式碼都放上去了,方便大家使用。

Repositories on GITHUB