当前位置: 首页 > news >正文

表格数据滚到底部-自动加载更多

最近在研究表格库, 毕竟很多时候都在做各种各样的报表, 于是想要了解一下常用的那种, 数据滑动到底, 它就自动加载更多数据是如何实现的. 就原理大致知晓, 无非是监控用户滚到快到底的时候, 触发新的数据请求追加一批数据即可. 关键的操作就是, 监控 scroll 事件. 于是还是想着简单写个 demo 强化一下学习.

实现思路

  • 先做一个固定宽高的表格容器, 并设置 overflow: auto 支持内容滚动
  • 预加载一批数据, 可以让用户看到滚动条
  • 监听用户的滚动行为, scroll 事件, 动态计算其离底部的 距离
  • 当用户滚动到底部的时候, 则发送请求加载一批新的数据追加进来
// 关键: 滚动监听 + 判断是否到底
const container = document.getElementById('scroll-container')function isScrolledToBottom(el) {const bottomDis = el.scrollHeight - (el.scrollTop + el.clientHeight)// console.log('bottomDis: ', bottomDis)return bottomDis < 20
}container.addEventListener('scroll', function() {if (isScrolledToBottom(container)) {loadMore() // 加载更多数据}
})
  • **scrollHeight: ** 可视区高度 + 滚动距离
  • scrollTop: 表示用户往下滚动的距离 (px). 当元素的样式设置了 overflow 且内容有溢出则会自带计算
  • clientHeight: ** 表示容器的可视区高度 (px)**

因此关键就是动态计算这个用户滚动时, 距离底部的距离:

const bottomDis = el.scrollHeight - (scrollTop + clientHeight)

这样设置一个阈值, 超过了就最追加更多数据即可.

整体实现 v1:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>表格滚动加载更多</title><style>#scroll-container {width: 400px;height: 400px;border: 1px solid #eee;overflow: auto;}table {width: 100%;border-collapse: collapse;}th, td {padding: 10px;border-bottom: 1px solid #eee;border-right: 1px solid #eee;text-align: left;}th {position: sticky;top: 0;z-index: 10;background-color: pink;}/* 加载提示 */#loading {text-align: center;color: #666;padding: 10px;display: none;}.loading-show {display: block !important;}</style>
</head>
<body><h2>表格到底部自动加载更多</h2><div id="scroll-container"><table><thead><tr><th>ID</th><th>姓名</th><th>邮箱</th></tr></thead><tbody id="table-body"><!-- 初始数据由 js 填充 --></tbody></table><div id="loading">正在加载更多...</div></div><script>// 模拟数据生成let nextId = 1const pageSize = 20function generateData(count) {const data = []for (let i = 0; i < count; i++) {data.push({id: nextId++,name: '用户' + (nextId - 1),email: 'user' + (nextId - 1) + '@example.com'})}return data }// 渲染表格行 function appendRows(data) {const tbody = document.getElementById('table-body')data.forEach(item => {const tr = document.createElement('tr')tr.innerHTML = `<td>${item.id}</td><td>${item.name}</td><td>${item.email}</td>`tbody.appendChild(tr)})}// 加载更多数据 (模拟网络请求)let isLoading = false // 防止重复加载let hasMore = true // 可能分页后面还有function loadMore() {if (isLoading || !hasMore) return isLoading = trueconst loadingEl = document.getElementById('loading')console.log(loadingEl)loadingEl.classList.add('loading-show')// 模拟网络延迟 1s setTimeout(() => {const newData = generateData(pageSize)appendRows(newData) isLoading = falseloadingEl.classList.remove('loading-show')// 模拟: 加载到 200 后停止 if (nextId > 200) {hasMore = falseloadingEl.textContent = '没有更多数据啦'loadingEl.classList.add('loading-show')}}, 1000)}// 关键: 滚动监听 + 判断是否到底const container = document.getElementById('scroll-container')function isScrolledToBottom(el) {const bottomDis = el.scrollHeight - (el.scrollTop + el.clientHeight)// console.log('bottomDis: ', bottomDis)return bottomDis < 20}container.addEventListener('scroll', function() {if (isScrolledToBottom(container)) {loadMore()}})// 初始化, 加载第一批数据window.addEventListener('load', () => {appendRows(generateData(pageSize))})</script>
</body>
</html>

都是 demo 为主, 目的还是去进一步强化这个滚动事件的学习. 但可以发现这个方案有一个弊端: 一直去动态监听, 性能消耗大. 针对这种数据滚动追加的方式, 更推荐用 IntersectionObserver 的方式更好一些.

整体实现 V2:

基于上面做优化

  • 在表格底部设置一个 哨兵元素
  • 监控这个哨兵管辖区域, 当被 "入侵" (isIntersecting) 时, 更新数据即可.
<table>....
</table>
<!-- 关键: 哨兵元素 -->
<div id="sentinel" style="height: 1px;"></div><div id="loading">正在加载更多...</div>
const observer = new IntersectionObserver((entries) => {// console.log(entries)entries.forEach(entry => {// 进入了哨兵视野区 20px, 就出发加载数据if (entry.isIntersecting && !isLoading) {loadMore()}})}, {root: container,rootMargin: '20px',threshold: 0,})observer.observe(sentinel)

完整如下:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>表格滚动加载更多</title><style>#scroll-container {width: 400px;height: 400px;border: 1px solid #eee;overflow: auto;}table {width: 100%;border-collapse: collapse;}th, td {padding: 10px;border-bottom: 1px solid #eee;border-right: 1px solid #eee;text-align: left;}th {position: sticky;top: 0;z-index: 10;background-color: pink;}/* 加载提示 */#loading {text-align: center;color: #666;padding: 10px;display: none;}.loading-show {display: block !important;}</style>
</head>
<body><h2>表格到底部自动加载更多 observer</h2><div id="scroll-container"><table><thead><tr><th>ID</th><th>姓名</th><th>邮箱</th></tr></thead><tbody id="table-body"><!-- 初始数据由 js 填充 --></tbody></table><!-- 关键: 哨兵元素 --><div id="sentinel" style="height: 1px;"></div><div id="loading">正在加载更多...</div></div><script>// 模拟数据生成let nextId = 1const pageSize = 20function generateData(count) {const data = []for (let i = 0; i < count; i++) {data.push({id: nextId++,name: '用户' + (nextId - 1),email: 'user' + (nextId - 1) + '@example.com'})}return data }// 渲染表格行 function appendRows(data) {const tbody = document.getElementById('table-body')data.forEach(item => {const tr = document.createElement('tr')tr.innerHTML = `<td>${item.id}</td><td>${item.name}</td><td>${item.email}</td>`tbody.appendChild(tr)})}// 加载更多数据 (模拟网络请求)let isLoading = false // 防止重复加载let hasMore = true // 可能分页后面还有function loadMore() {if (isLoading || !hasMore) return isLoading = trueconst loadingEl = document.getElementById('loading')loadingEl.classList.add('loading-show')// 模拟网络延迟 1s setTimeout(() => {const newData = generateData(pageSize)appendRows(newData) isLoading = falseloadingEl.classList.remove('loading-show')// 模拟: 加载到 200 后停止 if (nextId > 200) {hasMore = falseloadingEl.textContent = '没有更多数据啦'loadingEl.classList.add('loading-show')}}, 1000)}// Intersection Observer 核心const sentinel = document.getElementById('sentinel')const container = document.getElementById('scroll-container')const observer = new IntersectionObserver((entries) => {console.log(entries)entries.forEach(entry => {// 进入了哨兵视野区 20px, 就出发加载数据if (entry.isIntersecting && !isLoading) {loadMore()}})}, {root: container,rootMargin: '20px',threshold: 0,})observer.observe(sentinel)// 初始化, 加载第一批数据appendRows(generateData(20))</script>
</body>
</html>

关于最基本的滚动 scroll 动态监控事件, 还有相对静态的 Observer 监控就基本学习到这了. 在本案例中, 当然是 observer 的方式更为高效, 因为数据的更新方式是一直增量追加的, 这个其实会带来性能问题, 要解决它, 最流行的方式还是用 虚拟滚动, 这时候, scroll 就能发挥大作用了, 这里先到这吧.

http://www.jsqmd.com/news/73012/

相关文章:

  • 水刀切割机哪家好?2025热门切石机厂家权威排名汇总 - 栗子测评
  • 水刀切割机哪家好?2025热门切石机厂家权威排名汇总 - 栗子测评
  • AI狂飙时代:我们该学什么,未来在哪?
  • 石材抛光机厂家哪家好?2025热门石材切割机厂家口碑推荐 - 栗子测评
  • 矿山机哪家好?2025靠谱矿山开采设备厂家排名推荐 - 栗子测评
  • TVS 保护管工厂哪家好?这些优质厂商值得关注 - 栗子测评
  • 深圳视频推广哪家好?当然选深圳市万创科技有限公司 - 栗子测评
  • 2025温州ip打造推荐:这8家公司助力品牌形象升级 - 栗子测评
  • 电感工厂哪家好?这 8 家优质厂商为电子设备保驾护航 - 栗子测评
  • 深圳全网营销哪家好?首选深圳市万创科技有限公司 - 栗子测评
  • AEO公司哪家好? - 栗子测评
  • CF1065E Side Transmutations - crazy-
  • 2025线上少儿编程哪个机构好?高口碑线上少儿编程培训推荐 - 栗子测评
  • 深圳建站公司哪家好?推荐深圳市万创科技有限公司 - 栗子测评
  • 深圳抖音推广哪家好?首选推荐深圳市万创科技有限公司 - 栗子测评
  • 岩板切割机厂家推荐哪家?2025高性价比花岗岩切割机厂家排名 - 栗子测评
  • 推荐一家贴片磁珠工厂?深圳市递百科技术有限公司为首选 - 栗子测评
  • 深圳互联网公司哪家好?推荐专业的深圳市万创科技有限公司 - 栗子测评
  • 深圳互联网公司哪家好?推荐专业的深圳市万创科技有限公司 - 栗子测评
  • 短视频推广公司哪家好?优质的短视频推广公司推荐 - 栗子测评
  • 谷歌优化公司服务商有哪些? - 栗子测评
  • 谷歌推广公司服务商有哪些? - 栗子测评
  • GEO公司哪家好? 2025 GEO公司测评 - 栗子测评
  • 2025年COD消解仪行业十大品牌,行业优秀企业行业品牌排名公司推荐榜 - 品牌推荐大师1
  • Airflow - XCom
  • 2025深圳外贸推广哪家好?8 家服务商助力出海发展 - 栗子测评
  • EFT/B 快速脉冲群整改案例服务商推荐 - 栗子测评
  • 水质多参数分析仪行业十大品牌/国产国内品牌排行榜/十大国产品牌行业优秀企业行业品牌排名公司推荐榜 - 品牌推荐大师1
  • 2025年重庆全屋定制家具公司口碑榜:推荐的5款木质家具产品 - 讯息观点
  • 2025年锂电池销售厂家有哪些靠谱的选择? - 讯息观点