UNPKG

fs-virtual-waterfall

Version:

Vue3 虚拟瀑布流组件

3 lines (2 loc) 11.1 kB
(function(d,t){typeof exports=="object"&&typeof module<"u"?t(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],t):(d=typeof globalThis<"u"?globalThis:d||self,t(d.FsVirtualWaterfall={},d.Vue))})(this,function(d,t){"use strict";var S=document.createElement("style");S.textContent=`@charset "UTF-8";.fs-virtual-waterfall-container[data-v-78a52c03]{width:100%;height:100%;--shadow-color: 0, 0, 0;--shadow-opacity: .08;--card-bg: #fff;--text-primary: #333;--text-secondary: #999;--border-radius: 12px;--hover-translate: -5px;--hover-scale: var(--5b2b462a);--accent-color: #4299e1}.fs-virtual-waterfall-container.theme-light[data-v-78a52c03]{--shadow-color: 0, 0, 0;--shadow-opacity: .08;--card-bg: #fff;--text-primary: #333;--text-secondary: #999}.fs-virtual-waterfall-container.theme-dark[data-v-78a52c03]{--shadow-color: 0, 0, 0;--shadow-opacity: .2;--card-bg: #1a1a1a;--text-primary: #e0e0e0;--text-secondary: #777}.fs-virtual-waterfall-container.debug-mode .fs-virtual-waterfall-debug-column[data-v-78a52c03]{position:absolute;top:0;border:1px dashed rgba(255,0,0,.3);box-sizing:border-box;color:#ff000080;font-size:12px;padding:4px;pointer-events:none;z-index:1}.fs-virtual-waterfall-content[data-v-78a52c03]{width:100%;height:86%;overflow-y:auto;scrollbar-width:thin;scrollbar-color:rgba(0,0,0,.2) transparent;-webkit-overflow-scrolling:touch}.fs-virtual-waterfall-content[data-v-78a52c03]::-webkit-scrollbar{width:6px}.fs-virtual-waterfall-content[data-v-78a52c03]::-webkit-scrollbar-track{background:transparent}.fs-virtual-waterfall-content[data-v-78a52c03]::-webkit-scrollbar-thumb{background-color:#0003;border-radius:3px}.fs-virtual-waterfall-list[data-v-78a52c03]{position:relative;width:100%;min-height:100%;padding:2px}.fs-virtual-waterfall-loading[data-v-78a52c03]{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);display:flex;flex-direction:column;align-items:center;color:var(--text-secondary);z-index:5}.fs-virtual-waterfall-loading .loading-spinner[data-v-78a52c03]{width:40px;height:40px;border:3px solid rgba(0,0,0,.1);border-radius:50%;border-top-color:var(--accent-color);animation:spin-78a52c03 1s ease-in-out infinite;margin-bottom:10px}.fs-virtual-waterfall-loading .loading-text[data-v-78a52c03]{font-size:14px}@keyframes spin-78a52c03{to{transform:rotate(360deg)}}.fs-virtual-waterfall-empty[data-v-78a52c03]{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);color:var(--text-secondary);font-size:14px;z-index:5}.fs-virtual-waterfall-item[data-v-78a52c03]{position:absolute;box-sizing:border-box;padding:8px;filter:drop-shadow(0 4px 12px rgba(var(--shadow-color),var(--shadow-opacity)));will-change:transform;pointer-events:auto;z-index:2;animation:fadeInUp-78a52c03 .5s ease forwards;animation-delay:calc(var(--index, 0) * .05s)}.fs-virtual-waterfall-item-inner[data-v-78a52c03]{width:100%;height:100%;overflow:hidden;background-color:var(--card-bg);transition:all .3s ease;transform-origin:center;position:relative;display:flex;flex-direction:column}.fs-virtual-waterfall-item-inner.card-rounded[data-v-78a52c03]{border-radius:var(--border-radius)}.fs-virtual-waterfall-item-inner.card-square[data-v-78a52c03]{border-radius:0}.fs-virtual-waterfall-item-inner[data-v-78a52c03]:hover{transform:translateY(var(--hover-translate)) scale(var(--hover-scale));filter:drop-shadow(0 10px 16px rgba(var(--shadow-color),calc(var(--shadow-opacity) * 1.5)));z-index:3}.fs-virtual-waterfall-item-inner[data-v-78a52c03] img{width:100%;height:auto;object-fit:cover;transition:transform .4s ease;display:block;margin-bottom:5px}.fs-virtual-waterfall-item-inner[data-v-78a52c03] img:hover{transform:scale(1.05)}.fs-virtual-waterfall-item-inner[data-v-78a52c03] .waterfall-content{flex-shrink:0;min-height:70px;justify-content:center;padding:0 10px 10px}.fs-virtual-waterfall-item-inner[data-v-78a52c03] p{padding:0 12px;font-size:14px;color:var(--text-primary);line-height:1.5;margin:8px 0}.fs-virtual-waterfall-item-inner[data-v-78a52c03] p:first-of-type{margin-top:10px}.fs-virtual-waterfall-item-inner[data-v-78a52c03] p:last-of-type{margin-bottom:10px;color:var(--text-secondary);font-size:12px}@keyframes fadeInUp-78a52c03{0%{opacity:0;transform:translateY(30px)}to{opacity:1;transform:translateY(0)}}.fs-virtual-waterfall-footer[data-v-78a52c03]{margin-top:20px;padding-bottom:30px;width:100%;text-align:center}@media (prefers-color-scheme: dark){.fs-virtual-waterfall-container.theme-auto[data-v-78a52c03]{--shadow-color: 0, 0, 0;--shadow-opacity: .2;--card-bg: #1a1a1a;--text-primary: #e0e0e0;--text-secondary: #777}} `,document.head.appendChild(S);function B(s){let f=!1;return function(...e){f||(f=!0,window.requestAnimationFrame(()=>{s.apply(this,e),f=!1}))}}function z(s,f=300){let e=null;return function(...i){e&&clearTimeout(e),e=setTimeout(()=>{s.apply(this,i)},f)}}const M=s=>(t.pushScopeId("data-v-78a52c03"),s=s(),t.popScopeId(),s),H={key:1,class:"fs-virtual-waterfall-loading"},V=[M(()=>t.createElementVNode("div",{class:"loading-spinner"},null,-1)),M(()=>t.createElementVNode("div",{class:"loading-text"},"加载中...",-1))],F={key:2,class:"fs-virtual-waterfall-empty"},W=t.defineComponent({__name:"FsVirtualWaterFall",props:{data:{},loading:{type:Boolean,default:!1},hasMore:{type:Boolean,default:!0},gap:{default:20},column:{default:4},columnItemCount:{default:6},themeMode:{default:"auto"},cardStyle:{default:"rounded"},scrollBehavior:{default:"smooth"},emptyText:{default:"暂无数据"},initialHeight:{default:1e3},loadMoreThreshold:{default:200},hoverScale:{default:1.02},debug:{type:Boolean,default:!1}},emits:["loadMore","loadError"],setup(s,{emit:f}){const e=s;t.useCssVars(a=>({"5b2b462a":e.hoverScale}));const i=t.ref(),n=t.reactive({list:[],error:null}),p=t.reactive({viewWidth:0,viewHeight:0,start:0,get end(){return this.start+this.viewHeight}}),c=t.reactive({queue:Array(e.column).fill(0).map(()=>({list:[],height:0})),len:0}),q=t.computed(()=>!e.loading&&n.list.length===0),N=t.computed(()=>({[`theme-${e.themeMode}`]:!0,"debug-mode":e.debug})),L=t.computed(()=>({[`card-${e.cardStyle}`]:!0})),m=t.computed(()=>{if(!p.viewWidth)return 0;const a=Math.max(e.column,1),o=(a-1)*e.gap,l=p.viewWidth-o;return Math.floor(l/a)}),R=()=>{c.queue=Array(e.column).fill(0).map(()=>({list:[],height:0})),c.len=0};t.watch(()=>e.column,()=>{R(),n.list.length>0&&t.nextTick(()=>{b(),x(e.column*e.columnItemCount)})},{immediate:!1}),t.watch(()=>e.data,a=>{a&&a.length>0&&(n.list=t.markRaw([...a]),t.nextTick(()=>{b(),x(n.list.length)}))},{immediate:!0,deep:!0}),t.watch(()=>m.value,()=>{n.list.length>0&&m.value>0&&t.nextTick(()=>{b()})});const j=t.computed(()=>({height:`${w.value.maxHeight}px`,scrollBehavior:e.scrollBehavior})),A=t.computed(()=>({position:"absolute",left:"0",width:"100%",bottom:"0",transform:"translateY(0)",padding:"10px 0",zIndex:10})),k=t.computed(()=>c.queue.reduce((a,{list:o})=>a.concat(o),[])),_=t.computed(()=>!k.value||k.value.length===0?[]:k.value.filter(a=>a.h+a.y>p.start-500&&a.y<p.end+500)),w=t.computed(()=>{let a=0,o=0,l=1/0,r=-1/0;return c.queue.forEach(({height:u},h)=>{u<l&&(l=u,a=h),u>r&&(r=u,o=h)}),r<=0&&(r=e.initialHeight),{minIndex:a,maxIndex:o,minHeight:l,maxHeight:r}}),U=t.computed(()=>n.list.reduce((a,o)=>{if(m.value<=0)return a;const l=o.width/Math.max(o.height,1),r=Math.floor(m.value/l);return console.log(m.value,"xxx"),console.log(l,"aspectRatio"),a.set(o.id,{width:m.value,height:r}),a},new Map)),y=t.computed(()=>c.len<n.list.length),x=(a=e.column)=>{for(let o=0;o<a;o++){if(!y.value)return;const l=w.value.minIndex,r=c.queue[l];if(!r)return;const u=r.list[r.list.length-1]||null,h=n.list[c.len];if(!h)return;const g=Y(h,u,l);if(!g)return;r.list.push(g);const v=r.list.length>1?e.gap:0;r.height+=g.h+v,c.len++}},Y=(a,o,l)=>{if(!a)return null;const r=U.value.get(a.id);if(!r)return null;const u=r.width||0,h=r.height||0;let g=0;o&&(g=o.y+o.h+e.gap);const v=200;return console.log(h,v),console.log(h+v,"height + contentBuffer"),t.markRaw({item:a,y:g,h:h+v,style:{width:`${u}px`,height:`${h+v}px`,left:`${l*(u+e.gap)}px`,top:`${g}px`,"--index":l}})},b=()=>{c.queue=Array(e.column).fill(0).map(()=>({list:[],height:0})),c.len=0,n.list.length>0&&x(n.list.length)},E=B(()=>{if(!i.value)return;const{scrollTop:a,clientHeight:o}=i.value;p.start=a;const l=w.value.maxHeight-w.value.minHeight;if(!e.loading&&e.hasMore){const r=a+o>w.value.minHeight-e.loadMoreThreshold;!y.value&&r||l<o*.5&&!y.value?f("loadMore",c.len):y.value&&r&&x(e.column*2)}}),I=z(()=>{T(),b()},300),T=()=>{if(!i.value)return;const{clientWidth:a,clientHeight:o,scrollTop:l}=i.value;p.viewWidth=a||0,p.viewHeight=o||0,p.start=l||0},D=()=>{if(T(),n.list.length>0){const a=Math.min(n.list.length,Math.max(e.column*e.columnItemCount*3,n.list.length));x(a),setTimeout(()=>{if(i.value){const{scrollHeight:o,clientHeight:l}=i.value;o<=l&&e.hasMore&&f("loadMore",c.len)}},100)}i.value&&i.value.addEventListener("scroll",E),window.addEventListener("resize",I)},O=()=>{i.value&&i.value.removeEventListener("scroll",E),window.removeEventListener("resize",I)};return t.onMounted(()=>{t.nextTick(()=>{D()})}),t.onUnmounted(()=>{O()}),(a,o)=>(t.openBlock(),t.createElementBlock("div",{class:t.normalizeClass(["fs-virtual-waterfall-container",N.value])},[t.createElementVNode("div",{class:"fs-virtual-waterfall-content",ref_key:"contentRef",ref:i},[t.createElementVNode("div",{class:"fs-virtual-waterfall-list",style:t.normalizeStyle(j.value)},[_.value&&_.value.length>0?(t.openBlock(!0),t.createElementBlock(t.Fragment,{key:0},t.renderList(_.value,({item:l,style:r},u)=>(t.openBlock(),t.createElementBlock("div",{class:"fs-virtual-waterfall-item",key:l.id,style:t.normalizeStyle(r)},[t.createElementVNode("div",{class:t.normalizeClass(["fs-virtual-waterfall-item-inner",L.value])},[t.renderSlot(a.$slots,"item",{item:l},void 0,!0)],2)],4))),128)):t.createCommentVNode("",!0),a.loading&&n.list.length===0?(t.openBlock(),t.createElementBlock("div",H,V)):t.createCommentVNode("",!0),q.value?(t.openBlock(),t.createElementBlock("div",F,t.toDisplayString(e.emptyText||"暂无数据"),1)):t.createCommentVNode("",!0),n.list.length>0?(t.openBlock(),t.createElementBlock("div",{key:3,class:"fs-virtual-waterfall-footer",style:t.normalizeStyle(A.value)},[t.renderSlot(a.$slots,"footer",{},void 0,!0)],4)):t.createCommentVNode("",!0),e.debug&&m.value>0?(t.openBlock(!0),t.createElementBlock(t.Fragment,{key:4},t.renderList(e.column,l=>(t.openBlock(),t.createElementBlock("div",{key:`col-${l}`,class:"fs-virtual-waterfall-debug-column",style:t.normalizeStyle({left:`${(l-1)*(m.value+e.gap)}px`,width:`${m.value}px`,height:`${Math.max(...c.queue.map(r=>r.height),500)}px`})}," Column "+t.toDisplayString(l),5))),128)):t.createCommentVNode("",!0)],4)],512)],2))}}),P="",C=((s,f)=>{const e=s.__vccOpts||s;for(const[i,n]of f)e[i]=n;return e})(W,[["__scopeId","data-v-78a52c03"]]),$={install:s=>{s.component("FsVirtualWaterFall",C)}};d.FsVirtualWaterFall=C,d.debounce=z,d.default=$,d.rafThrottle=B,Object.defineProperties(d,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});