实现效果,假如当前浏览的是第121条视频
首先需要先准备要用到的工具函数,和模拟接口回调函数
api.js
//模拟根据当前 id返回 该id前面有多少条视频
export function getOffset(id) {
return new Promise(resolve => {
resolve(121)
})
}
//模拟返回一个具有分页功能的图片列表的函数
export function getVideo(pageNo, pageSize) {
return new Promise(resolve => {
// let page = Math.ceil(pageNo/pageSize) //Calculates the number of pages.
let start = (pageNo - 1) * pageSize; //Calculates the start index.
let end = start + pageSize; //Calculates the end index.
let arr = []; //Declaring an array.
for (let i = start; i < end; i++) { //For loop to add the image to the array.
let obj = { id: i, cover: `https://picsum.photos/200/${i}` }
arr.push(obj)
}
resolve(arr) //Resolve the promise.
})
}
工具函数
utils.js
//防抖
export function debounce(fn, delay = 500) {
let timer = null;
return function () {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
fn.apply(this, arguments)
timer = null
}, delay)
}
}
//根据页码,和数量获取到当前 对应的下标范围
export function getIndexRange(pageNo, pageSize) {
const start = (pageNo - 1) * pageSize; // -1 to compensate for 0 indexing. 0-0 is 0. So -
const end = start + pageSize - 1; // compensate for 0-0 being 0. So end is the same as start. So end = start. So
return [start, end]
}
//根据下标,和数量,计算出在哪一页
export function getPage(index, size) {
return Math.ceil((index + 1) / size)
}
主要运用逻辑在两个函数
createElement 动态创建列表节点 loadPages 加载对应索引页的内容 主函数页面import { getOffset, getVideo } from './api.js'
import { debounce, getIndexRange, getPage } from './utils.js'
const currentId = 100 //当前看过视频的id
const SIZE = 10 //分页的size
const continer = document.querySelector('.continer')
const indicator = document.querySelector('.indicator')
let visibleIndex = new Set() //用于存放出现在视口中元素的 索引值
const ob = new IntersectionObserver(entires => { //创建一个元素监听器,监听 每个视频的item
for(const entry of entires){
const index = +entry.target.dataset.index;
if(entry.isIntersecting){ // isIntersecting:表示这个元素是否出现在视口中
visibleIndex.add(index)
} else {
visibleIndex.delete(index)
}
}
loadPagesDebounce() //加载这些索引对应的内容
})
function getRange() { //获取视口中索引值集合的 最大和最小
if(visibleIndex.size === 0) return [0,0]
const min = Math.min(...visibleIndex)
const max = Math.max(...visibleIndex)
return [min, max]
}
function createElement(page) { //手动创建 需要加载的所有节点
const childrenLen = continer.children.length
const count = page * SIZE - childrenLen;
for (let i = 0; i < count; i++) {
const item = document.createElement('div')
item.className = 'item'
item.dataset.index = i + childrenLen
continer.appendChild(item)
ob.observe(item) //为所有节点添加监听器
}
}
function loadPages(){
//得到当前可以看到的索引范围的内容
const [minIndex, maxIndex] = getRange()
const pages = new Set()
for (let i = minIndex; i <= maxIndex; i++) {
pages.add(getPage(i, SIZE)) //获取当前视口中需要加载的页面集合pages
}
for (const page of pages) {
const [minIndex, maxIndex] = getIndexRange(page, SIZE)
// console.log(minIndex, maxIndex)
if (continer.children[minIndex].dataset.loaded) { //防止已经加载过的重复加载
continue;
}
continer.children[minIndex].dataset.loaded = true
getVideo(page, SIZE).then(async (res) => { //循坏模拟获取数据的列表
for (let i = minIndex; i <= maxIndex; i++) {
const item = continer.children[i] //item is a div element.
const offset = await getOffset(currentId)
item.innerHTML = `
<img src="${res[i - minIndex].cover}" />
<span style='color:#f00'>${i} ${item.dataset.index == offset ? '---刚刚看过!' : ''}</span>
`
}
})
}
setIndicatorVisible()
}
//判断当前位置是否需要展示刚刚看过的按钮
async function setIndicatorVisible(){
const offset = await getOffset(currentId)
const [minIndex, maxIndex] = getRange() //currentId is a div element. offset is the top left of the element. (0,0) is the top left of
const page = getPage(offset, SIZE)
// console.log(minIndex, maxIndex, offset)
if(offset>=minIndex && offset<=maxIndex){
indicator.style.display = 'none' //display the indicator element. (the div element) (the top left of the element) (0,
} else indicator.style.display = 'block'
indicator.dataset.page = page
indicator.dataset.index = offset
}
indicator.onclick = () => {
const page = +indicator.dataset.page //page is a number. + indicator.dataset.page is a string. + indicator
const index = +indicator.dataset.index //index is a number. + indicator.dataset.index is a string
createElement(page)
continer.children[index].scrollIntoView({
behavior:'smooth',
block:'center'
})
}
const loadPagesDebounce = debounce(loadPages, 300)
createElement(1) //首次先加载一页
html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<style>
/* body,html{
position: relative;
} */
.continer{
display: grid;
/* grid-gap: 20px; */
grid-template-columns: 1fr 1fr 1fr;
grid-column-gap: 10px;
grid-row-gap: 15px;
/* flex-wrap: wrap; */
padding: 0 200px;
box-sizing: border-box;
}
.item{
width: 200px;
height: 300px;
border: 1px solid #000;
margin-bottom: 20px;
padding-bottom: 20px;
}
.item img{
width: 200px;
height: 280px;
object-fit: cover;
}
.indicator{
position: fixed;
left: 0;
right: 0;
bottom: 20px;
width: 100px;
margin: 0 auto;
text-align: center;
/* display: none; */
background: #f00;
color: #fff; /* for IE */
}
</style>
<body>
<div class="continer">
</div>
<div class="indicator">前往刚刚看过</div>
</body>
<script type="module" src="./loadPages/index.js"></script>
<script type="module" src="./loadPages/api.js"></script>
</html>
标签:function,index,const,查看,item,抖音,let,刚刚,page From: https://www.cnblogs.com/xuhuang/p/17452559.html