UNPKG

@ionic/core

Version:
1 lines 7.92 kB
const t=window.Ionic.h,e="item",i="header",s="footer",n=0,r=1,l=2,o=2;function h(t,n){const r=function(t,n){switch(n){case e:return t.querySelector("template:not([name])");case i:return t.querySelector("template[name=header]");case s:return t.querySelector("template[name=footer]")}}(t,n);return r&&t.ownerDocument?t.ownerDocument.importNode(r.content,!0).children[0]:null}function a(t,n,r,l,h,a,c,d,p,u){const g=[],m=u+p;for(let u=p;u<m;u++){const p=t[u];if(r){const e=r(p,u,t);null!=e&&g.push({i:d++,type:i,value:e,index:u,height:h,reads:o,visible:!1})}if(g.push({i:d++,type:e,value:p,index:u,height:n?n(p,u):c,reads:n?0:o,visible:!!n}),l){const e=l(p,u,t);null!=e&&g.push({i:d++,type:s,value:e,index:u,height:a,reads:2,visible:!1})}}return g}class c{constructor(){this.range={offset:0,length:0},this.viewportHeight=0,this.cells=[],this.virtualDom=[],this.isEnabled=!1,this.viewportOffset=0,this.currentScrollTop=0,this.indexDirty=0,this.lastItemLen=0,this.totalHeight=0,this.approxItemHeight=45,this.approxHeaderHeight=30,this.approxFooterHeight=30}itemsChanged(){this.calcCells(),this.updateVirtualScroll()}async componentDidLoad(){const t=this.el.closest("ion-content");t?(await t.componentOnReady(),this.contentEl=t,this.scrollEl=await t.getScrollElement(),this.calcCells(),this.updateState()):console.error("virtual-scroll must be used inside ion-content")}componentDidUpdate(){this.updateState()}componentDidUnload(){this.scrollEl=void 0}onScroll(){this.updateVirtualScroll()}onResize(){this.updateVirtualScroll()}positionForItem(t){return Promise.resolve(function(t,i,s){const n=i.find(i=>i.type===e&&i.index===t);return n?s[n.i]:-1}(t,this.cells,this.getHeightIndex()))}checkRange(t,e=-1){if(!this.items)return;const i=-1===e?this.items.length-t:e,s=function(t,e){return 0===e?0:e===(t[t.length-1].index||0)+1?t.length:t.findIndex(t=>t.index===e)}(this.cells,t),n=a(this.items,this.itemHeight,this.headerFn,this.footerFn,this.approxHeaderHeight,this.approxFooterHeight,this.approxItemHeight,s,t,i);this.cells=function(t,e,i){if(0===i&&e.length>=t.length)return e;for(let s=0;s<e.length;s++)t[s+i]=e[s];return t}(this.cells,n,s),this.lastItemLen=this.items.length,this.indexDirty=Math.max(t-1,0),this.scheduleUpdate()}checkEnd(){this.items&&this.checkRange(this.lastItemLen)}updateVirtualScroll(){this.isEnabled&&this.scrollEl&&(this.timerUpdate&&(clearTimeout(this.timerUpdate),this.timerUpdate=void 0),this.queue.read(this.readVS.bind(this)),this.queue.write(this.writeVS.bind(this)))}readVS(){const{contentEl:t,scrollEl:e,el:i}=this;let s=0,n=i;for(;n&&n!==t;)s+=n.offsetTop,n=n.parentElement;this.viewportOffset=s,e&&(this.viewportHeight=e.offsetHeight,this.currentScrollTop=e.scrollTop)}writeVS(){const t=this.indexDirty,e=function(t,e,i){return{top:Math.max(t-100,0),bottom:t+e+100}}(this.currentScrollTop-this.viewportOffset,this.viewportHeight),i=this.getHeightIndex(),s=function(t,e,i){const s=e.top,n=e.bottom;let r=0;for(;r<t.length&&!(t[r]>s);r++);const l=Math.max(r-2-1,0);for(;r<t.length&&!(t[r]>=n);r++);return{offset:l,length:Math.min(r+2,t.length)-l}}(i,e);(function(t,e,i){return t<=i.offset+i.length||e.offset!==i.offset||e.length!==i.length})(t,this.range,s)&&(this.range=s,function(t,e,i,s){for(const e of t)e.change=n,e.d=!0;const o=[],h=s.offset+s.length;for(let n=s.offset;n<h;n++){const s=i[n],l=t.find(t=>t.d&&t.cell===s);if(l){const t=e[n];t!==l.top&&(l.top=t,l.change=r),l.d=!1}else o.push(s)}const a=t.filter(t=>t.d);for(const i of o){const s=a.find(t=>t.d&&t.cell.type===i.type),n=i.index;s?(s.d=!1,s.change=l,s.cell=i,s.top=e[n]):t.push({d:!1,cell:i,visible:!0,change:l,top:e[n]})}t.filter(t=>t.d&&-9999!==t.top).forEach(t=>{t.change=r,t.top=-9999})}(this.virtualDom,i,this.cells,s),this.nodeRender?function(t,e,i,s){const r=Array.from(t.children).filter(t=>"TEMPLATE"!==t.tagName),o=r.length;let a;for(let c=0;c<i.length;c++){const d=i[c],p=d.cell;if(d.change===l){if(c<o)e(a=r[c],p,c);else{const i=h(t,p.type);(a=e(i,p,c)||i).classList.add("virtual-item"),t.appendChild(a)}a.$ionCell=p}else a=r[c];d.change!==n&&(a.style.transform=`translate3d(0,${d.top}px,0)`);const u=p.visible;d.visible!==u&&(u?a.classList.remove("virtual-loading"):a.classList.add("virtual-loading"),d.visible=u),p.reads>0&&(s(p,a),p.reads--)}}(this.el,this.nodeRender,this.virtualDom,this.updateCellHeight.bind(this)):this.domRender?this.domRender(this.virtualDom):this.renderItem&&this.el.forceUpdate())}updateCellHeight(t,e){const i=()=>{if(e.$ionCell===t){const i=this.win.getComputedStyle(e),s=e.offsetHeight+parseFloat(i.getPropertyValue("margin-bottom"));this.setCellHeight(t,s)}};e&&e.componentOnReady?e.componentOnReady().then(i):i()}setCellHeight(t,e){const i=t.i;t===this.cells[i]&&(t.visible=!0,t.height!==e&&(t.height=e,this.indexDirty=Math.min(this.indexDirty,i),this.scheduleUpdate()))}scheduleUpdate(){clearTimeout(this.timerUpdate),this.timerUpdate=setTimeout(()=>this.updateVirtualScroll(),100)}updateState(){const t=!(!this.scrollEl||!this.cells);t!==this.isEnabled&&(this.enableScrollEvents(t),t&&this.updateVirtualScroll())}calcCells(){this.items&&(this.lastItemLen=this.items.length,this.cells=a(this.items,this.itemHeight,this.headerFn,this.footerFn,this.approxHeaderHeight,this.approxFooterHeight,this.approxItemHeight,0,0,this.lastItemLen),this.indexDirty=0)}getHeightIndex(){return this.indexDirty!==1/0&&this.calcHeightIndex(this.indexDirty),this.heightIndex}calcHeightIndex(t=0){this.heightIndex=function(t,e){if(!t)return new Uint32Array(e);if(t.length===e)return t;if(e>t.length){const i=new Uint32Array(e);return i.set(t),i}return t.subarray(0,e)}(this.heightIndex,this.cells.length),this.totalHeight=function(t,e,i){let s=t[i];for(let n=i;n<t.length;n++)t[n]=s,s+=e[n].height;return s}(this.heightIndex,this.cells,t),this.indexDirty=1/0}enableScrollEvents(t){this.scrollEl&&(this.isEnabled=t,this.enableListener(this,"scroll",t,this.scrollEl))}renderVirtualNode(t){const{type:n,value:r,index:l}=t.cell;switch(n){case e:return this.renderItem(r,l);case i:return this.renderHeader(r,l);case s:return this.renderFooter(r,l)}}hostData(){return{style:{height:`${this.totalHeight}px`}}}render(){if(this.renderItem)return t(d,{dom:this.virtualDom},this.virtualDom.map(t=>this.renderVirtualNode(t)))}static get is(){return"ion-virtual-scroll"}static get properties(){return{approxFooterHeight:{type:Number,attr:"approx-footer-height"},approxHeaderHeight:{type:Number,attr:"approx-header-height"},approxItemHeight:{type:Number,attr:"approx-item-height"},checkEnd:{method:!0},checkRange:{method:!0},domRender:{type:"Any",attr:"dom-render"},el:{elementRef:!0},enableListener:{context:"enableListener"},footerFn:{type:"Any",attr:"footer-fn"},headerFn:{type:"Any",attr:"header-fn"},itemHeight:{type:"Any",attr:"item-height",watchCallbacks:["itemsChanged"]},items:{type:"Any",attr:"items",watchCallbacks:["itemsChanged"]},nodeRender:{type:"Any",attr:"node-render"},positionForItem:{method:!0},queue:{context:"queue"},renderFooter:{type:"Any",attr:"render-footer"},renderHeader:{type:"Any",attr:"render-header"},renderItem:{type:"Any",attr:"render-item"},totalHeight:{state:!0},win:{context:"window"}}}static get listeners(){return[{name:"scroll",method:"onScroll",disabled:!0},{name:"window:resize",method:"onResize",passive:!0}]}static get style(){return"ion-virtual-scroll{display:block;position:relative;width:100%;contain:strict;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.virtual-loading{opacity:0}.virtual-item{left:0;right:0;top:0;position:absolute;-webkit-transition-duration:0ms;transition-duration:0ms;will-change:transform}"}}const d=({dom:t},e,i)=>i.map(e,(e,i)=>{const s=t[i],n=e.vattrs||{};let r=n.class||"";return r+="virtual-item ",s.visible||(r+="virtual-loading"),Object.assign({},e,{vattrs:Object.assign({},n,{class:r,style:Object.assign({},n.style,{transform:`translate3d(0,${s.top}px,0)`})})})});export{c as IonVirtualScroll};