前言
有的时候,我们会遇到网页中,一切内容只有在分页中才有,但是又需要在当前页面中展示。例如获取分页文章信息实现首页的无限加载效果。
现在就以获取分页文章为例,直接上代码
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的主要功能大概就是监测某个元素是否进入视图,进入则执行特定功能。因为我们已经将点击加载事件写好了,所以我们只要监测文章列表底部的加载按钮进入视图,就执行点击事件即可。
这样的好处就是省去监测滚动之类的麻烦事。
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会监测不到导致只会加载第一次。