91 lines
2.5 KiB
JavaScript
91 lines
2.5 KiB
JavaScript
const vueSticky = {};
|
||
let listenAction;
|
||
vueSticky.install = Vue => {
|
||
Vue.directive("sticky", {
|
||
inserted(el, binding) {
|
||
const params = binding.value || {};
|
||
const stickyTop = params.stickyTop || 0;
|
||
const zIndex = params.zIndex || 1000;
|
||
const elStyle = el.style;
|
||
|
||
elStyle.position = "-webkit-sticky";
|
||
elStyle.position = "sticky";
|
||
// if the browser support css sticky(Currently Safari, Firefox and Chrome Canary)
|
||
// if (~elStyle.position.indexOf('sticky')) {
|
||
// elStyle.top = `${stickyTop}px`;
|
||
// elStyle.zIndex = zIndex;
|
||
// return
|
||
// }
|
||
const elHeight = el.getBoundingClientRect().height;
|
||
const elWidth = el.getBoundingClientRect().width;
|
||
elStyle.cssText = `top: ${stickyTop}px; z-index: ${zIndex}`;
|
||
|
||
const parentElm = el.parentNode || document.documentElement;
|
||
const placeholder = document.createElement("div");
|
||
placeholder.style.display = "none";
|
||
placeholder.style.width = `${elWidth}px`;
|
||
placeholder.style.height = `${elHeight}px`;
|
||
parentElm.insertBefore(placeholder, el);
|
||
|
||
let active = false;
|
||
|
||
const getScroll = (target, top) => {
|
||
const prop = top ? "pageYOffset" : "pageXOffset";
|
||
const method = top ? "scrollTop" : "scrollLeft";
|
||
let ret = target[prop];
|
||
if (typeof ret !== "number") {
|
||
ret = window.document.documentElement[method];
|
||
}
|
||
return ret;
|
||
};
|
||
|
||
const sticky = () => {
|
||
if (active) {
|
||
return;
|
||
}
|
||
if (!elStyle.height) {
|
||
elStyle.height = `${el.offsetHeight}px`;
|
||
}
|
||
|
||
elStyle.position = "fixed";
|
||
elStyle.width = `${elWidth}px`;
|
||
placeholder.style.display = "inline-block";
|
||
active = true;
|
||
};
|
||
|
||
const reset = () => {
|
||
if (!active) {
|
||
return;
|
||
}
|
||
|
||
elStyle.position = "";
|
||
placeholder.style.display = "none";
|
||
active = false;
|
||
};
|
||
|
||
const check = () => {
|
||
const scrollTop = getScroll(window, true);
|
||
const offsetTop = el.getBoundingClientRect().top;
|
||
if (offsetTop < stickyTop) {
|
||
sticky();
|
||
} else {
|
||
if (scrollTop < elHeight + stickyTop) {
|
||
reset();
|
||
}
|
||
}
|
||
};
|
||
listenAction = () => {
|
||
check();
|
||
};
|
||
|
||
window.addEventListener("scroll", listenAction);
|
||
},
|
||
|
||
unbind() {
|
||
window.removeEventListener("scroll", listenAction);
|
||
}
|
||
});
|
||
};
|
||
|
||
export default vueSticky;
|