sg-scroll
Version:
102 lines (90 loc) • 3.06 kB
JavaScript
/**
* @param {Event} e
*/
const sgScroll = function ({ target }) {
// 判断滚动容器的top内边距是否缓存
if (target.sgPaddingTop === undefined) {
target.sgPaddingTop =
parseInt(getComputedStyle(target).paddingTop) || 0;
}
const paddingTop = target.sgPaddingTop;
const scrollTop = target.scrollTop;
// 暂不考虑一开始设置到滚动容器的内联样式
target.style.paddingTop = "";
// 重置元素的内联样式
let stickyEl = target.sgStickyEl;
if (stickyEl) {
stickyEl.style.width = "";
stickyEl.style.position = "";
stickyEl.style.top = "";
stickyEl.classList.remove("sg-sticking");
}
// 获取所有能够粘滞的元素
const children = [...target.children].filter((el) => {
return el.classList.contains("sg-sticky-item");
});
// 找到最后一个产生粘滞的元素
let index = -1;
for (let i = children.length - 1; i >= 0; i--) {
if (children[i].offsetTop - scrollTop < paddingTop) {
index = i;
break;
}
}
if (index === -1) {
return;
}
stickyEl = children[index];
const stickyClientHeight = stickyEl.clientHeight;
// 判断下一个即将粘滞的元素,用于粘滞元素过渡计算
const nextIndex = index + 1;
let nextPadding = 0;
if (nextIndex < children.length) {
const offset = children[nextIndex].offsetTop - scrollTop - paddingTop;
if (offset < stickyClientHeight) {
nextPadding = stickyClientHeight - offset;
}
}
// 先获取高度后再设置定位
stickyEl.style.width = stickyEl.clientWidth + "px";
stickyEl.style.position = "absolute";
// stickyEl.style.top = paddingTop + scrollTop - nextPadding + "px";
stickyEl.style.top = paddingTop - nextPadding + "px";
stickyEl.classList.add("sg-sticking");
target.sgStickyEl = stickyEl;
// 判断缓存元素的上下间隔
if (target.sgStickElMargin === undefined) {
const style = getComputedStyle(stickyEl);
target.sgStickElMargin =
parseInt(style.marginTop) + parseInt(style.marginBottom);
}
// 设置滚动容器的top边距
target.style.paddingTop =
paddingTop + stickyClientHeight + target.sgStickElMargin + "px";
}
const rootEl = document.body
export default {
init: function () {
if (rootEl._sgIsStickyInit) {
return
}
rootEl._sgIsStickyInit = true
const actionStartEvent = function (e) {
let scrollEl = e.target
while(scrollEl) {
if (scrollEl.getAttribute("sg-sticky") === "sg-sticky-item") {
if (scrollEl._sgIsStickyInit) {
return
}
scrollEl._sgIsStickyInit = true
scrollEl.parentElement.style.position = 'relative'
scrollEl.addEventListener('scroll', sgScroll)
break
}
scrollEl = scrollEl.parentElement
}
}
rootEl.addEventListener('touchstart', actionStartEvent)
rootEl.addEventListener('mousedown', actionStartEvent)
}
}