JS获取分页信息实现异步加载,配合IntersectionObserver API实现自动加载

前言 有的时候,我们会遇到网页中,一切内容只有在分页中才有,但是又需要在当前页面中展示。例如获取分页文章信息实现首页的无限加载效果。 现在就以获取分页文章为例,直接上代码 loadMoreArticles() { if (!ThemeConfig.enable_index_list_ajax){

前言

有的时候,我们会遇到网页中,一切内容只有在分页中才有,但是又需要在当前页面中展示。例如获取分页文章信息实现首页的无限加载效果。

现在就以获取分页文章为例,直接上代码

loadMoreArticles() {
		if (!ThemeConfig.enable_index_list_ajax){
			return
		}
		// 在页面加载完成后执行
		$(document).ready(() => {
			const $domLoadContainer = $(".joe_load_container");
			$domLoadContainer.on('click','.joe_load', async function () {
				const $domLoad = $(".joe_load");
				this.domNext = $domLoad.attr('data-next');
				// console.log(this.domNext)
				$domLoad.html("加载中...").attr("loading", "true");
				fetch(this.domNext, {
					method: "GET",
				})
					.then((response) => response.text())
					.then((html) => {
						const parser = new DOMParser();
						const doc = parser.parseFromString(html, "text/html");
						const postListElement = document.querySelector(".joe_list");
						// console.log(postListElement)
						const postListNewElements = doc.querySelectorAll(".joe_list .joe_list__item");
						// console.log(postListNewElements)

						if (postListNewElements && postListNewElements.length > 0) {
							postListNewElements.forEach((element) => {
								postListElement.appendChild(element.cloneNode(true));
							});

						}
						const $newDomLoad = $(doc).find(".joe_load");
						if ($newDomLoad.attr('data-next') !== '/') {
							$domLoadContainer.empty().append($newDomLoad);
						} else {
							$domLoadContainer.remove();
						}
						// 向下滚动一段距离
						const lastItemTop = postListElement.querySelector(".joe_list__item:last-child").offsetTop;
						const scrollTop = lastItemTop - window.innerHeight; // Adjust the value as needed
						window.scrollTo({
							top: scrollTop,
							behavior: 'smooth'
						});

					})
					.catch((error) => {
						console.error(error);
					})
					.finally(() => {

					});
			});
		});
	},

过程

首先获取触发的DOM $domLoadContainer(我这里是用的jQuery方法,同理即可),然后将点击事件绑定到其中的.joe_load

const $domLoadContainer = $(".joe_load_container");  
$domLoadContainer.on('click','.joe_load', async function () { const $domLoad = $(".joe_load");

获取到data-next中的下一页链接地址,我的HTML部分是这样的

<div class="joe_load_container"
     th:with="nextPage = ${posts.totalPages == posts.page?'':posts.nextUrl}">
     <div class="joe_load" th:data-next="@{${nextPage}}">查看更多 </div>
</div>

fetch(this.domNext, {method: "GET"}):使用 fetch 函数异步获取下一页的文章内容。this.domNext就是获取到的要请求的地址。

.then((response) => response.text()):将获取到的响应转换为文本。

parser.parseFromString(html, "text/html"):使用 DOMParser 将响应的文本内容解析为一个 DOM 文档对象。

随后就是获取到你想要的信息,我这里想要获取的是分页中的文章信息和分页中下一页的信息

const postListNewElements = doc.querySelectorAll(".joe_list .joe_list__item");
const $newDomLoad = $(doc).find(".joe_load");

获取分页中的下一页链接是为了更新请求链接,实现全部文章的加载。

利用.appendChild(element.cloneNode(true));方式将获取到的信息添加到你想要的位置因为我获取到的是NodeList

的集合,所以使用的是cloneNode 这里根据需求自行改写即可。

最后就是利用一点判断在加载完所有文章后删除标签。

使用IntersectionObserver Api实现自动加载效果

这个实现起来也非常简单,这个api的主要功能大概就是监测某个元素是否进入视图,进入则执行特定功能。因为我们已经将点击加载事件写好了,所以我们只要监测文章列表底部的加载按钮进入视图,就执行点击事件即可。

766c3f6d06a8feb0f6a7ac2368a111d4.png
这样的好处就是省去监测滚动之类的麻烦事。

const ob =  new IntersectionObserver(entries => {
            const domClick = document.querySelector('.joe_load')
            if (entries[0].isIntersecting){
                domClick.click()
            }

        }, {
            threshold:1
        })
        const loading = document.querySelector('.joe_load_container')
        ob.observe(loading)

具体用法可以自行搜索,这里简单讲一下。threshold是IntersectionObserver的配置,意思是当元素进入多少时开始执行,范围是0-1,我这里是让加载按钮完全进入视图才加载。还有其他设置这里用不到就留空默认ob.observe(loading)就是写要检测的元数。

然后因为我这里只监测一个,所以直接entries[0].isIntersecting ,如果是多个元数可以用entries.forEach(entry => {}遍历每一个元素。最后.click()触发点击,功能完成。

这里有一点要注意的是,因为在获取下一页信息的方法中,我的点击对象的DOM结构是有变化的,所以我检测的是它上一级的.joe_load_container,否则,有变化的DOM会监测不到导致只会加载第一次。