无限滚动 Infinite Scroll

实现效果

预览

准备工作

数据

使用了jsonplaceholder的数据。点击此处查看测试数据

我们可以添加参数:_limit(表示每页几条数据)和_page(表示第几页):

https://jsonplaceholder.typicode.com/posts?_limit=5&_page=2

HTML与CSS

我们需要一个列表容器:

<div class="posts-container" id="posts-container"></div>

一个loader动画:

<div class="loader">
<div class="circle"></div>
<div class="circle"></div>
<div class="circle"></div>
</div>

完整HTMLCSS查看Github源代码

fetch API

jsonplaceholder推荐的获取方式是使用fetch

fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(response => response.json())
.then(json => console.log(json))

fetch方法传入一个url作为参数,返回一个Promise对象。

fetch请求成功之后,得到的是一个Response对象。response.json()也是一个异步操作,取出所有内容,转化为JSON对象。获取到数据之后,我们便可以渲染到页面了。

实现

要实现无限滚动的效果,我们需要监听windowscroll事件,滚动触底的时候再触发请求数据的操作。

请求数据

由于我们之后在滚动触底的时候还需要渲染数据,所以将请求封装一下:

let limit = 5; // 每次请求5条数据
let page = 1;

function fetchData() {
return fetch(`${url}/posts?_limit=${limit}&_page=${page}`).then((response) =>
response.json()
);
}

function showData() {
fetchData().then((data) => {
// 渲染数据
render(data);
});
}

渲染数据

将获取到的数据(数组形式)渲染到页面:

function render(data) {
data.forEach((post) => {
const postEl = document.createElement("div");
postEl.classList.add("post");
postEl.innerHTML = `<div class="number">${post.id}</div>
<div class="post-info">
<div class="post-title">${post.title}</div>
<p class="post-body">${post.body}</p>
</div>`;
postsContainer.appendChild(postEl);
});
}

判断滚动触底

window.addEventListener("scroll", () => {
const { scrollTop, scrollHeight, clientHeight } = document.documentElement;
if (scrollTop + clientHeight >= scrollHeight - 10) {
// 请求数据
page++;
showData();
}
});

这里会出现滚动触底之后会请求多次的情况,这个问题需要用到函数节流技术解决。

使用async / await 简化

在使用到Promise的地方,可以用async / await 改写,简化代码。

async function fetchData() {
let res = await fetch(`${url}/posts?_limit=${limit}&_page=${page}`);
return await res.json();
}

async function showData() {
let data = await fetchData();
render(data);
}

函数节流

函数节流,指定时间间隔内只会执行一次任务。

本项目中,滚动触底时会多次触发scroll事件,因此会发送多次请求。函数节流技术可以解决这个问题:

// 加载更多数据
function load() {
page++;
showData();
}

function throttle(fn, delay) {
let canUse = true;
return function () {
if (canUse) {
fn.apply(this, arguments);
canUse = false;
setTimeout(() => (canUse = true), delay);
}
};
}
const throttled = throttle(load, 1000);

完整代码

完整代码请查看Github

参考

Check if a user has scrolled to the bottom

Author: kpt

Permalink: http://kpt.ink/2021/09/15/Infinite-Scroll/

文章默认使用 CC BY-NC-SA 4.0 协议进行许可,使用时请注意遵守协议。