UNPKG

@joyday/vue-loop-scroll

Version:

A high-performance Vue component for loop scrolling, supporting large data sets, adaptive resizing, real-time data updates, and flexible scrolling controls.

2 lines (1 loc) 9.3 kB
"use strict";require('../assets/main.css');var be=Object.defineProperty;var Pe=(a,t,n)=>t in a?be(a,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):a[t]=n;var ee=(a,t,n)=>Pe(a,typeof t!="symbol"?t+"":t,n);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("vue");class _ extends Error{constructor(n){super(n);ee(this,"cancelled");this.cancelled=!0,Object.setPrototypeOf(this,_.prototype)}}const Ce=a=>{let t=0,n=!1;return{execute:async function(...h){const I=t;n=!0;try{const B=await a.apply(this,h);if(I!==t)throw new _("Async operation cancelled");return B}finally{n=!1}},cancel:()=>{n&&(t++,n=!1)},isCancellable:()=>n,isCancelledError:h=>h instanceof _}},Me=()=>{const a=s.ref(0);return{updateCounter:a,triggerUpdate:()=>{a.value++}}};function te(a,t){let n=null;const l=s.computed(()=>"ResizeObserver"in window),r=()=>{n&&(n.disconnect(),n=null)},d=s.watch(()=>s.toValue(a),h=>{r(),h&&l.value&&(n=new window.ResizeObserver(t),n.observe(h))},{immediate:!0,flush:"post"});return s.onBeforeUnmount(()=>{d(),r()}),{isSupported:l,stop:()=>{d()}}}function V(a){if(!(a!=null&&a.offsetParent))return{width:0,height:0};const t=a.getBoundingClientRect(),n=window.getComputedStyle(a),l=P=>parseFloat(P)||0,r=l(n.borderLeftWidth)+l(n.borderRightWidth),d=l(n.borderTopWidth)+l(n.borderBottomWidth);return{width:t.width-r,height:t.height-d}}let ze=0;const Re=()=>String(ze++),Be=(a,t,n="forward")=>{const l=a.length-1;let r=0;if(n==="forward")for(;r<=l;)t(a[r],r),r++;else{let d=l;for(;d>=0;)t(a[d],d),d--}};function Te(a){const t=typeof a;return a!=null&&t==="object"}const We=(a,t)=>{const n=setTimeout(()=>t==null?void 0:t(),a);return()=>clearTimeout(n)},F=new WeakMap;function _e(a,t){let n=!0;const{resolve:l,promise:r}=Ee(),P=We(a,()=>{l(!1)}),h=Object.defineProperty(r,"isRunning",{get:()=>n});return F.set(h,()=>{n&&(n=!1,P(),l(!0))}),r.finally(()=>{n=!1,F.delete(h)}),h}function Ae(a){var t;(t=F.get(a))==null||t()}function Ee(){let a,t;return{promise:new Promise((l,r)=>{a=l,t=r}),resolve:a,reject:t}}const He=["data-uid","data-key"],De=s.defineComponent({__name:"index",props:{dataSource:{},itemKey:{},direction:{default:"up"},speed:{default:1},waitMode:{default:"item"},waitTime:{default:0},pausedOnHover:{type:Boolean,default:!0},loadCount:{default:1}},setup(a){const t=a,n=s.ref(null),l=s.ref(null),r=s.shallowRef([]);let d,P,h=[];const I=s.reactive({viewportWidth:0,viewportHeight:0,trackWidth:0,trackHeight:0}),B={scrollOffset:0,scrollOffsetInPageMode:0,isScrolling:!1,isPaused:!1},f=s.reactive({...B}),ne=()=>{Object.assign(f,{...B})},k=s.computed(()=>["up","down"].includes(t.direction)),x=s.computed(()=>["up","left"].includes(t.direction)),O=s.computed(()=>k.value?I.viewportHeight:I.viewportWidth),U=s.computed(()=>k.value?I.trackHeight:I.trackWidth),oe=s.computed(()=>U.value>O.value),se=s.computed(()=>{let e=f.scrollOffset;return x.value?e*=-1:e+=O.value-U.value,{transform:`translate3D(${k.value?`0, ${e}px, 0`:`${e}px, 0, 0`})`}}),R=s.computed(()=>t.waitTime>0),A=s.computed(()=>Math.max(Math.min(t.speed,O.value),Number.MIN_VALUE)),{execute:K,cancel:ae,isCancellable:ie}=Ce(s.nextTick),{updateCounter:re,triggerUpdate:E}=Me(),ce=()=>{if(!l.value)return 0;const{height:o,width:i}=V(l.value);return k.value?o:i},le=()=>{const e=h[h.length-1];return(e==null?void 0:e.key)??""},ue=()=>{t.pausedOnHover&&!f.isPaused&&f.isScrolling&&(f.isPaused=!0,T())},de=()=>{t.pausedOnHover&&f.isPaused&&f.isScrolling&&(f.isPaused=!1,L(d==null?void 0:d.isRunning))},q=async()=>(d=_e(t.waitTime),await d),fe=()=>{d!=null&&d.isRunning&&(Ae(d),d=null)},$=e=>{try{return Te(e)&&t.itemKey&&e[t.itemKey]!=null?String(e[t.itemKey]):JSON.stringify(e)}catch{return""}},H=e=>({value:e,uid:Re(),key:$(e)}),D=()=>{var e;return Array.from(((e=l.value)==null?void 0:e.children)??[])},X=e=>{const{totalWidth:o,totalHeight:i}=e.reduce((c,p)=>(c.totalHeight+=p.height,c.totalWidth+=p.width,c),{totalWidth:0,totalHeight:0});return k.value?i:o},he=()=>V(n.value),ge=()=>V(l.value),Y=()=>{const e=he(),o=ge();Object.assign(I,{viewportHeight:e.height,viewportWidth:e.width,trackHeight:o.height,trackWidth:o.width})},J=e=>t.dataSource.findIndex(o=>$(o)===e),pe=e=>{h=G(e)},ve=()=>{P&&(cancelAnimationFrame(P),P=void 0)},T=()=>{ve(),fe()},j=()=>{T(),ne(),h=[]},G=e=>{const o=[],i=l.value;if(!i)return o;const c=ce();let p;const{top:u,left:w}=i.getBoundingClientRect(),C=g=>{const v=x.value?g.bottom-u:c-(g.top-u),m=x.value?g.right-w:c-(g.left-w);return{bottom:v,right:m}},S=g=>{const v=x.value?g.previousElementSibling:g.nextElementSibling;return v?C(v.getBoundingClientRect()):{bottom:0,right:0}};return Be(e,g=>{const v=g.getBoundingClientRect();let{bottom:m,right:M}=p??S(g);const y=m,b=M,{bottom:z,right:N}=C(v),xe=z-y,Oe=N-b;p={bottom:z,right:N},o.push({uid:g.dataset.uid||"",key:g.dataset.key||"",width:Oe,height:xe,top:y,bottom:z,left:b,right:N})},x.value?"forward":"reverse"),o},W=async(e,o,i)=>{const c=t.dataSource.length,p=r.value.length,u=i==="next";let w=0;const C=t.dataSource.length*2,S=async()=>{if(w++>C)return;let g=t.loadCount;const v=[];for(;g-- >0;){e=(e+c)%c;const z=x.value?"push":"unshift";v[z](H(t.dataSource[e])),u?e++:e--}const m=x.value&&u||!x.value&&!u;r.value=m?r.value.concat(v):v.concat(r.value),await K();const M=m?D().slice(p):D().slice(0,r.value.length-p),y=G(M),b=X(y);M.length>0&&o>b?await S():(pe(D()),Y())};await S()},L=async(e=!0)=>{if(f.isScrolling=!0,f.isPaused)return;const o=(u,w)=>{const C=h.length,S=y=>k.value?y.height:y.width;let g=w,v=0,m=0;const M=t.dataSource.length;for(;!(m++>M);){const y=S(h[g]);v+=y;const b=(g+1)%C,z=v+S(h[b]);if(u<v)break;if(u<z)return{hasCrossedItem:!0,nextItemIndex:b,remainingOffset:u-v};g=b}return{hasCrossedItem:!1,nextItemIndex:w,remainingOffset:u}};let{remainingOffset:i,nextItemIndex:c}=o(f.scrollOffset,0);const p=async()=>{f.scrollOffset+=A.value,i+=A.value,f.scrollOffsetInPageMode+=A.value;const{hasCrossedItem:u,remainingOffset:w,nextItemIndex:C}=o(i,c);if(u){c=C,i=w;const v=t.waitMode==="item"&&R.value,m=t.waitMode==="page"&&R.value&&f.scrollOffsetInPageMode>=O.value;(v||m)&&(i-=w,f.scrollOffset-=w),m&&(f.scrollOffsetInPageMode-=w)}if(f.scrollOffset>=O.value){const v=x.value?r.value.slice(c):r.value.slice(0,-c),m=h.slice(c),M=X(m),y=O.value*2-(M-i);if(y>0){r.value=v,h=m,c=0,f.scrollOffset=i;const b=J(le()),z=b>-1?b+1:0;await W(z,y,"next")}}const S=t.waitMode==="item"&&u&&R.value,g=t.waitMode==="page"&&u&&f.scrollOffsetInPageMode>=O.value&&R.value;g&&(f.scrollOffsetInPageMode=0),!((S||g)&&await q())&&await new Promise((v,m)=>{P=requestAnimationFrame(async()=>{try{await p(),v()}catch(M){m(M)}})})};R.value&&e&&await q()||await p()},me=async(e,o,i)=>{const c=H(e);r.value=[c];const{marginBefore:p,marginAfter:u}=i;p>0&&await W(o-1,p,"pre"),u>0&&await W(o+1,u,"next");const C=(()=>{const S=h.find(g=>g.uid===c.uid);return S?k.value?S.top:S.left:0})()-p;f.scrollOffset=C},we=()=>{let e=f.scrollOffset;const o=h.length,i=[];let c=!1,p=0;for(;p<o;){const u=h[p];c&&i.push(u);const w=k.value?u.height:u.width;if(e-=w,e<0){if(c)break;i.push(u),c=!0,e+=O.value}p++,p>=o&&(p=0)}return i},Se=e=>{const o=k.value?e.height:e.width,c=(k.value?e.top:e.left)-f.scrollOffset,u=O.value-c-o+O.value;return{marginBefore:c,marginAfter:u}},ye=()=>{const e=we();for(const[,o]of e.entries()){const i=J(o.key);if(i>-1)return{status:"found",item:t.dataSource[i],index:i,margins:Se(o)}}return{status:"not-found"}},Ie=async()=>{const e=ye();e.status==="found"?(await me(e.item,e.index,e.margins),await L(d==null?void 0:d.isRunning)):(j(),r.value=[],await Q())},Q=async()=>{await W(0,O.value*2,"next"),await L()},Z=e=>e.map(o=>H(o)),ke=async()=>{const e=Math.ceil(t.dataSource.length/t.loadCount);let o=0;const i=r.value;for(;o++<e;){const c=t.dataSource.slice(0,t.loadCount*(o+1));if(x.value||c.reverse(),r.value=Z(c),await K(),Y(),oe.value)return r.value=i,!0}return r.value=Z(t.dataSource),!1};return s.onMounted(()=>{s.watch(()=>[t.dataSource,re.value],async()=>{try{if(ie()&&ae(),f.isScrolling&&T(),!await ke()){j();return}f.isScrolling?await Ie():await Q()}catch{}},{immediate:!0,deep:!0}),s.watch(()=>t.direction,()=>{j(),E()}),te(n,e=>{const{blockSize:o,inlineSize:i}=e[0].contentBoxSize[0];(o!==I.viewportHeight||i!==I.viewportWidth)&&E()}),te(l,e=>{const{blockSize:o,inlineSize:i}=e[0].contentBoxSize[0];(o!==I.trackHeight||i!==I.trackWidth)&&E()})}),s.onBeforeUnmount(()=>{T()}),(e,o)=>r.value.length>0?(s.openBlock(),s.createElementBlock("div",{key:0,ref_key:"scrollViewportRef",ref:n,class:s.normalizeClass(["scroll-loop-viewport",[k.value?"direction-vertical":"direction-horizontal",x.value?"direction-forward":"direction-backward"]]),onMouseenter:ue,onMouseleave:de},[s.createElementVNode("div",{ref_key:"scrollTrackRef",ref:l,class:"scroll-loop-track",style:s.normalizeStyle(se.value)},[(s.openBlock(!0),s.createElementBlock(s.Fragment,null,s.renderList(r.value,i=>(s.openBlock(),s.createElementBlock("div",{class:"scroll-loop-item","data-uid":i.uid,"data-key":i.key,key:i.uid},[s.renderSlot(e.$slots,"default",s.mergeProps({ref_for:!0},{item:i.value}),()=>[s.createTextVNode(s.toDisplayString(i.value),1)],!0)],8,He))),128))],4)],34)):s.createCommentVNode("",!0)}}),je=(a,t)=>{const n=a.__vccOpts||a;for(const[l,r]of t)n[l]=r;return n},Le=je(De,[["__scopeId","data-v-17f09cf5"]]);exports.LoopScroll=Le;