// github L6zt
滚动插件设计原理
- 获取滚动元素的视口高度viewH和滚动高度scrollH,得出 滚动轴最大滚动距离 scrollMaxTop = viewH – scrollH;
- 根据滚动时计算滚动时滚动轴的滚动高度 scrollTop 与 scrollMaxTop, 比较做差,判断是否触发动作。
- 加入节流函数->优化性能。
- 借鉴过饿了vue滚动指令
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.item {
height: 20px;
background: black;
margin-bottom: 20px;
}
.view {
height: 100px;
overflow: auto;
}
</style>
</head>
<body>
<div class="view">
</div>
</body>
<script src="./jquery.js"></script>
<script>
// 节流函数
let uuid = 1;
const thrFn = ({
fn,
time,
maxTime
}) => {
let timeK = null;
let oTime = (new Date()).getTime();
const execFn = function () {
fn.apply(null, arguments);
oTime = (new Date()).getTime();
}
return function() {
const nTime = (new Date).getTime();
let args = arguments;
clearTimeout(timeK);
if (nTime - oTime > maxTime) {
execFn.call(null, ...args);
} else {
timeK = setTimeout(() => {
execFn.call(null, ...args)
}, time);
}
}
}
const scroll = ({
container = window, // 滚动容器
fn, //触发加载时 回调函数
triggerT = 50, // 触发距离
time = 100, // 节流函数
maxTime = 200, // 节流函数 最大触发时间
immediate = false,// 初始化后是否 直接触发回调函数。
loadingHtml = '<div class="ee-loading" style="padding: 20px; font-size: 16px; text-align: center">加载中</div>'
}) => {
const $elem = $(container);
const elem = $elem.get(0);
const $elemT = (elem === window ? $(window) : $elem);
// 初始化高度
let startY = 0;
const $loading = $(loadingHtml);
// 是否显示loading
const showLoading = (flag) => {
const $container = elem === window ? $('body') : $elem;
if (flag === true) {
$container.append($loading);
} else {
$loading.remove();
}
}
// 监听
const fixFn = thrFn({
fn,
time,
maxTime
});
// 获取元素滚动轴 距离容器顶部高度
const MakeScrollTop = (elem) => {
return () => {
if (elem === window) {
return window.pageYOffset || window.document.documentElement.scrollTop
}
return elem.scrollTop
}
};
// 获取 元素滚动高度
const scrollHeight = (elem) => {
if (elem === window) {
return window.document.documentElement.scrollHeight || window.document.body.scrollHeight
}
return elem.scrollHeight
}
// 设置元素 滚动轴距离 顶部高度
const setScrollTop = (y) => {
if (elem === window) {
window.pageYOffset = window.document.documentElement.scrollTop = y;
return
}
elem.scrollTop = y;
}
const getScrollTop = MakeScrollTop(elem);
const eventFn = () => {
// 当前滚动距离
let currentY = getScrollTop();
// 当前容器真实高度
let height = $elem.height();
// console.log(height);
// 当前容器最大滚动距离
let allY = scrollHeight(elem) - height;
// 方向判断 触发版判断
if (currentY - startY > 0 && allY - currentY <= triggerT) {
fixFn(showLoading, currentY);
}
startY = currentY;
}
$elemT.on('scroll', eventFn);
const offScroll = () => {
$elemT.off('scroll', eventFn);
}
immediate && fn(showLoading, 0);
return {
offScroll,
setScrollTop
}
};
// 使用代码
const htmlTemplate = `<div class="item">num</div>`
const list = new Array(8).fill(true);
let time = 0;
let busy = false;
const fn = function(load, y) {
console.log(y);
if (busy === false) {
busy = true;
load(true);
setTimeout(() => {
load(false)
busy = false;
time++;
const str = list.map(item => htmlTemplate).join('').replace(/num/g, time);
$('.view').append(str);
}, 2000)
}
};
const handler = scroll({
container: $('.view'),
fn,
immediate: true
})
</script>
</html>