vue-virtual-list-observer
Version:
keyword: **intersectionObserver scroll-list Scroll animation,quick scroll resolved**
3 lines (2 loc) • 7.69 kB
JavaScript
var __defProp=Object.defineProperty,__defNormalProp=(t,e,i)=>e in t?__defProp(t,e,{enumerable:!0,configurable:!0,writable:!0,value:i}):t[e]=i,__publicField=(t,e,i)=>(__defNormalProp(t,"symbol"!=typeof e?e+"":e,i),i);!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports,require("vue")):"function"==typeof define&&define.amd?define(["exports","vue"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self)["vue-virtual-list"]={},t.Vue)}(this,(function(t,e){"use strict";class i{constructor(t){__publicField(this,"getWindowFirstIndex",(t=>{const{currentIndex:e}=this.domDataCache,i=Math.floor(this.listSize/2);let o;return o=t?e+i:e-i,o<0&&(o=0),o})),this.opsCheck(t)}opsCheck(t){if(!t||"object"!=typeof t)throw new Error("options are illegal");const{itemHeight:e,container:i,listSize:o,renderFunction:s,getDomHeightFunction:r,_setScoll:n,scrollDom:l,scrollAnima:a}=t;if(!e||"number"!=typeof e)throw new Error("itemHeight is illegal");if(!s||"function"!=typeof s)throw new Error("lastItemId is illegal");if(!o)throw new Error("listSize is illegal");if(!i||!i.nodeType)throw new Error("root is illegal");this.itemHeight=e,this.container=i,this.listSize=o,this.renderFunction=s,this.getDomHeightFunction=r,this.firstItem=document.getElementsByClassName("_first"),this.lastItem=document.getElementsByClassName("_last"),this.startEntry=0,this._setScoll=n,this.scrollDom=l,this.scrollAnima=a,this.domDataCache={currentPaddingTop:0,currentPaddingBottom:0,topSentinelPreviousY:0,topSentinelPreviousRatio:0,bottomSentinelPreviousY:0,bottomSentinelPreviousRatio:0,currentIndex:0}}updateDomDataCache(t){Object.assign(this.domDataCache,t)}getArrSum(t,e,i){let o=0;for(let s=e;s<i;s++)o+=t[s];return o}adjustPaddings(t,e){if(0===e&&!1===t&&0===this.startEntry)return this.startEntry=1,!1;const{container:i,itemHeight:o}=this,{currentPaddingTop:s,currentPaddingBottom:r}=this.domDataCache;let n,l,a=o*Math.floor(this.listSize/2),c=Math.floor(this.listSize/2);if(t){let t=this.getDomHeightFunction(),i=e-c,o=e;a=this.getArrSum(t,i,o),n=s+a,l=0===r?0:r-a}else{if(0!==e){let t=this.getDomHeightFunction(),i=e+this.listSize,o=i+c;a=this.getArrSum(t,i,o)}n=s+a,l=r+a,n=0===s?0:s-a}0===e&&(l=0),i.style.paddingBottom=`${l}px`,i.style.paddingTop=`${n}px`,this.updateDomDataCache({currentPaddingTop:n,currentPaddingBottom:l})}async topItemCb(t){const{topSentinelPreviousY:e,topSentinelPreviousRatio:i}=this.domDataCache,o=t.boundingClientRect.top,s=t.intersectionRatio,r=t.isIntersecting;if(o>e&&r&&s>=i){const t=this.getWindowFirstIndex(!1);await this.renderFunction(t),await this.adjustPaddings(!1,t),await this.updateDomDataCache({currentIndex:t,topSentinelPreviousY:o,topSentinelPreviousRatio:s})}else this.updateDomDataCache({topSentinelPreviousY:o,topSentinelPreviousRatio:s})}async bottomItemCb(t){const{bottomSentinelPreviousY:e,bottomSentinelPreviousRatio:i}=this.domDataCache,o=t.boundingClientRect.top,s=t.intersectionRatio,r=t.isIntersecting;if(o<e&&s>=i&&r){const t=this.getWindowFirstIndex(!0);await this.renderFunction(t),await this.adjustPaddings(!0,t),await this.updateDomDataCache({currentIndex:t,bottomSentinelPreviousY:o,bottomSentinelPreviousRatio:s})}else this.updateDomDataCache({bottomSentinelPreviousY:o,bottomSentinelPreviousRatio:s})}initIntersectionObserver(){this.observer=new IntersectionObserver((t=>{t.forEach((t=>{t.target.className.split(" ").includes("_first")?this.topItemCb(t):t.target.className.split(" ").includes("_last")&&this.bottomItemCb(t)}))}),{}),this.observer.observe(this.firstItem[0]),this.observer.observe(this.lastItem[0])}scrollToTop(){this.domDataCache={currentIndex:0,currentPaddingTop:0,currentPaddingBottom:0,topSentinelPreviousY:0,topSentinelPreviousRatio:0,bottomSentinelPreviousY:0,bottomSentinelPreviousRatio:0},this.scrollAnima?this.animationToTop(this.scrollDom):(this.renderFunction(0),this.scrollDom.scrollTop=0,this.container.style.paddingTop="0px",this.container.style.paddingBottom="0px"),this.startEntry=0,this.startObserver()}async scrollToIndex(t){this.domDataCache,await this.renderFunction(t),await this.getPadding(t),this.updateDomDataCache({currentIndex:t})}getPadding(t){let e=t,i=this.getDomHeightFunction();const o=this.getArrSum(i,0,e);this.container.style.paddingBottom="0px",this.container.style.paddingTop=`${o}px`,this.scrollDom.scrollTop=o,this.updateDomDataCache({currentPaddingTop:o,currentPaddingBottom:0,bottomSentinelPreviousY:0,topSentinelPreviousY:o})}startObserver(){this.initIntersectionObserver()}animationToTop(t){const e=Date.now(),i=t.scrollTop,o=window.requestAnimationFrame||(t=>setTimeout(t,16)),s=()=>{const r=(Date.now()-e)/500;if(r<1){const e=t=>Math.pow(t,3),n=t=>t<.5?e(2*t)/2:1-e(2*(1-t))/2;t.scrollTop=i*(1-n(r)),o(s)}else t.scrollTop=0};o(s)}}const o={name:"ListDOM",data:()=>({itemsArr:null,arrDom:[],arrDomHeight:[],arrDomHeightPrefix:[],listScrollIns:null,container:null,judgeToTop:0}),emits:["request"],props:{resArr:{type:Array,default:[],required:!0},visualDomCount:{type:Number,default:5,required:!0},domHeight:{type:Number,default:150},listHeight:{type:Number},scrollInstance:{required:!0},scrollAnima:{type:Boolean,default:!0}},inject:["request"],mounted(){const t=this.scrollInstance();this.arrDom=this.resArr,this.container=document.getElementById("list"),document.querySelectorAll("#m-listContainer li");const e=async t=>{let e=0,i=0;for(;t+5*this.visualDomCount>this.resArr.length&&i<5;)if(await this.request(),i++,1===this.judgeToTop){this.judgeToTop=0;break}await(()=>{t+5*this.visualDomCount>this.resArr.length?(e=this.resArr.length,this.arrDom=this.resArr.slice(t)):(e=t+5*this.visualDomCount,this.arrDom=this.resArr.slice(t,t+5*this.visualDomCount)),this.$nextTick((()=>{for(let i=t;i<e;i++)this.arrDomHeight[i]=this.$refs.itemDom[i-t].clientHeight}))})()},o=()=>this.arrDomHeight;this.$nextTick((()=>{const s=document.querySelectorAll(".list-item");s[0].classList.add("_first"),s[s.length-1].classList.add("_last"),e(0);this.listScrollIns=new i({container:this.container,listSize:5*this.visualDomCount,itemHeight:this.domHeight,renderFunction:async t=>{await e(t)},getDomHeightFunction:()=>o(),scrollDom:t,scrollAnima:this.scrollAnima}),this.listScrollIns.startObserver()})),this.MonitorScroll()},methods:{scrollToTop:function(){this.scrollInstance(),this.listScrollIns.scrollToTop(),this.judgeToTop=1},getScroll:function(){return this.$refs.list.scrollTop},getSize:function(){return this.resArr.length},scrollToIndex:function(t){this.listScrollIns.scrollToIndex(t)},MonitorScroll:function(){setInterval((()=>{let t=parseInt(this.container.style.paddingTop.slice(0,-2));let e=this.scrollInstance().scrollTop;if(t>e+200){let[t,i]=this.getIndex(e);this.scrollToIndex(t)}else{if(e>this.$refs.list.clientHeight-parseInt(this.container.style.paddingBottom.slice(0,-2))+100){let[t,i]=this.getIndex(e);this.scrollToIndex(t)}}}),100)},getIndex:function(t){let e=0,i=0,o=0;for(let s=0;s<this.arrDomHeight.length;s++){if(e+=this.arrDomHeight[s],!(e<=t))return[i,o];i=s,o=e}return[i,o]}}},s={class:"list",id:"list",ref:"list"};var r=((t,e)=>{const i=t.__vccOpts||t;for(const[o,s]of e)i[o]=s;return i})(o,[["render",function(t,i,o,r,n,l){return e.openBlock(),e.createElementBlock("div",s,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(n.arrDom,((i,o)=>(e.openBlock(),e.createElementBlock("div",{class:"list-item",key:o,ref_for:!0,ref:"itemDom"},[e.renderSlot(t.$slots,"list",{item:i},void 0,!0)])))),128)),e.renderSlot(t.$slots,"footer",{},void 0,!0)],512)}],["__scopeId","data-v-b21dcff2"]]);t.ListDOM=r,Object.defineProperties(t,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
//# sourceMappingURL=vue-virtual-list.umd.js.map