UNPKG

vue-sticky-directive-ts

Version:

A powerful vue directive make element sticky.

2 lines (1 loc) 5.27 kB
"use strict";var f=Object.defineProperty;var m=(s,t,e)=>t in s?f(s,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):s[t]=e;var n=(s,t,e)=>(m(s,typeof t!="symbol"?t+"":t,e),e);Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});var u=require("vue");const a="@@vue-sticky-directive",k=["resize","scroll","touchstart","touchmove","touchend","pageshow","load"],y=["width","top","left","right","bottom","paddingTop"],l={topOffset:0,bottomOffset:0,shouldTopSticky:!1,shouldBottomSticky:!1,zIndex:10,on:()=>{}};function b(s,t){return typeof t=="string"?t:(t=t.toString(10),y.includes(s)?`${t}px`:t)}function p(s,t={},e={}){if(!!s){for(const o in t)s.style.setProperty(o,b(o,t[o]));for(const o in e)e[o]&&!s.classList.contains(o)?s.classList.add(o):!e[o]&&s.classList.contains(o)&&s.classList.remove(o)}}class d{constructor(t,e={}){n(this,"el");n(this,"containerEl");n(this,"placeholderEl");n(this,"listeners",[]);n(this,"isPending",!1);n(this,"state");n(this,"callbackState");n(this,"options",l);this.el=t,this.state={isTopSticky:!1,isBottomSticky:!1,height:0,width:0,xOffset:0,placeholderElTop:0,containerElTop:0,containerElBottom:0},this.callbackState={top:!1,bottom:!1,sticked:!1},this.setOptions(e),this.containerEl=this.getContainerEl();const o=this.el.parentNode||this.containerEl;this.placeholderEl=document.createElement("div"),o.insertBefore(this.placeholderEl,this.el),this.setListeners().then(()=>{},()=>{})}setOptions(t={}){const e=t.side&&["top","bottom","both"].includes(t.side)?t.side:"top";this.options={topOffset:Number(t.topOffset)||l.topOffset,bottomOffset:Number(t.bottomOffset)||l.bottomOffset,shouldTopSticky:e==="top"||e==="both",shouldBottomSticky:e==="bottom"||e==="both",zIndex:Number(t.zIndex)||l.zIndex,on:t.on||l.on}}async setListeners(){if(this.listeners.length>0)return;const t=this.update.bind(this);await u.nextTick(()=>{const e=[window,this.containerEl];k.forEach(o=>{e.forEach(i=>{this.listeners.push(()=>i==null?void 0:i.removeEventListener(o,t)),i==null||i.addEventListener(o,t,{passive:!0})})})})}doUnbind(){this.listeners.forEach(t=>t()),this.listeners=[],this.resetElement()}updateOptions(t={}){this.setOptions(t),this.recomputeState(),this.updateElements()}update(){this.isPending||(requestAnimationFrame(()=>{this.isPending=!1,this.recomputeState(),this.updateElements()}),this.isPending=!0)}isTopSticky(){if(!this.options.shouldTopSticky)return!1;const t=this.state.placeholderElTop,e=this.state.containerElBottom,o=this.options.topOffset,i=this.options.bottomOffset;return t<=o&&e>=i}isBottomSticky(){if(!this.options.shouldBottomSticky)return!1;const t=window.innerHeight-this.state.placeholderElTop-this.state.height,e=window.innerHeight-this.state.containerElTop,o=this.options.topOffset,i=this.options.bottomOffset;return t<=i&&e>=o}recomputeState(){const t=this.el.getBoundingClientRect(),e=this.placeholderEl.getBoundingClientRect(),o=this.containerEl.getBoundingClientRect();this.state=Object.assign({},this.state,{height:t.height,width:e.width,xOffset:e.left,placeholderElTop:e.top,containerElTop:o.top,containerElBottom:o.bottom}),this.state.isTopSticky=this.isTopSticky(),this.state.isBottomSticky=this.isBottomSticky()}fireEvents(){typeof this.options.on=="function"&&(this.callbackState.top!==this.state.isTopSticky||this.callbackState.bottom!==this.state.isBottomSticky||this.callbackState.sticked!==(this.state.isTopSticky||this.state.isBottomSticky))&&(this.callbackState={top:this.state.isTopSticky,bottom:this.state.isBottomSticky,sticked:this.state.isBottomSticky||this.state.isTopSticky},this.options.on())}updateElements(){const t={paddingTop:0},e={position:"static",top:"auto",bottom:"auto",left:"auto",width:"auto",zIndex:this.options.zIndex},o={"vue-sticky-placeholder":!0},i={"vue-sticky-el":!0,"top-sticky":!1,"bottom-sticky":!1},r=this.state.height+this.options.bottomOffset+this.options.topOffset;if(this.state.isTopSticky||this.state.isBottomSticky?(e.position="fixed",e.left=this.state.xOffset,e.width=this.state.width,t.paddingTop=this.state.height):t.paddingTop=0,this.state.isTopSticky){i["top-sticky"]=!0,e.top=this.options.topOffset;const c=this.state.containerElBottom-r;c<0&&(e.top+=c)}if(this.state.isBottomSticky){i["bottom-sticky"]=!0,e.bottom=this.options.bottomOffset;const c=window.innerHeight-this.state.containerElTop-r;c<0&&(e.bottom+=c)}p(this.el,e,i),p(this.placeholderEl,t,o),this.fireEvents()}resetElement(){var t,e;["position","top","bottom","left","width","zIndex"].forEach(o=>{this.el.style.removeProperty(o)}),this.el.classList.remove("bottom-sticky","top-sticky"),(e=(t=this.placeholderEl)==null?void 0:t.parentNode)==null||e.removeChild(this.placeholderEl)}getContainerEl(){var e;let t=this.el.parentElement;for(;t&&t.tagName!=="HTML"&&t.tagName!=="BODY"&&t.nodeType===1;){if(t.hasAttribute("sticky-container"))return t;t=t.parentElement}return(e=this.el.parentElement)!=null?e:document.body}}const h={mounted:"mounted",updated:"updated",beforeUnmount:"beforeUnmount"},E={[h.mounted](s,t){(t.value===void 0||t.value)&&(s[a]=new d(s,t.value))},[h.updated](s,t){s[a]&&s[a].updateOptions(t.value)},[h.beforeUnmount](s){s[a]&&(s[a].doUnbind(),s[a]=void 0)}},S={install:s=>{s.directive("Sticky",E)}};exports.Sticky=d;exports.default=S;