Skip to content

Commit 13ebb0e

Browse files
committed
0.0.1.1
1 parent 7de2011 commit 13ebb0e

File tree

4 files changed

+114
-154
lines changed

4 files changed

+114
-154
lines changed

README.md

Lines changed: 0 additions & 80 deletions
This file was deleted.

pages/pics.html

Lines changed: 86 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
<!DOCTYPE html>
1+
<!DOCTYPE html>
22
<html lang="zh-CN" class="dark">
33
<head>
44
<meta charset="UTF-8">
55
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6-
<title>NexusFlow V2 - 修复增强版</title>
6+
<title>NexusFlow</title>
77

88
<script src="https://cdn.tailwindcss.com"></script>
99

@@ -39,14 +39,8 @@
3939
opacity: 0;
4040
}
4141

42-
.grid-item {
43-
width: calc(50% - 16px);
44-
margin-bottom: 24px;
45-
opacity: 0; /* 初始不可见,等待动画 */
46-
}
47-
48-
@media (min-width: 768px) { .grid-item { width: calc(33.333% - 16px); } }
49-
@media (min-width: 1280px) { .grid-item { width: calc(20% - 16px); } }
42+
#gallery { position: relative; }
43+
.grid-item { position: absolute; width: 0; margin-bottom: 0; opacity: 0; will-change: transform; }
5044

5145
.img-container {
5246
transform-style: preserve-3d;
@@ -125,9 +119,9 @@ <h1 class="text-xl font-bold tracking-widest">NEXUS<span class="text-neon">FLOW<
125119

126120
<!-- JS 库 -->
127121
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
128-
<script src="https://unpkg.com/masonry-layout@4/dist/masonry.pkgd.min.js"></script>
129-
<script src="https://unpkg.com/imagesloaded@5/imagesloaded.pkgd.min.js"></script>
122+
130123
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>
124+
<script src="wallpaper.js"></script>
131125

132126
<script>
133127
// --- 配置 ---
@@ -138,48 +132,76 @@ <h1 class="text-xl font-bold tracking-widest">NEXUS<span class="text-neon">FLOW<
138132

139133
// 状态变量
140134
let isLoading = false;
141-
let msnry; // Masonry 实例
135+
let columns = 0;
136+
let colHeights = [];
137+
let colLefts = [];
138+
let columnWidth = 0;
142139

143-
// API 源
144-
const apiSources = [
145-
{ name: 'Picsum', fn: (w, h) => `https://picsum.photos/id/${Math.floor(Math.random()*1000)}/${w}/${h}` },
146-
{ name: 'LoremFlickr', fn: (w, h) => `https://loremflickr.com/${w}/${h}/cyberpunk,neon,tech?random=${Math.random()}` },
147-
{ name: 'PlaceIMG', fn: (w, h) => `https://placeimg.com/${w}/${h}/tech?t=${Math.random()}` }
148-
];
140+
// 使用聚合抓取函数 fetchWallpapers(来自 wallpaper.js)替代所有单一图片 API
149141

150-
// --- 1. 初始化 Masonry ---
151-
// 使用原生 JS 初始化,便于控制
152142
const grid = document.querySelector('#gallery');
153-
msnry = new Masonry(grid, {
154-
itemSelector: '.grid-item',
155-
columnWidth: '.grid-item',
156-
gutter: CONFIG.gutter,
157-
percentPosition: true,
158-
transitionDuration: 0 // 关闭 Masonry 自带动画,用 GSAP
159-
});
143+
function computeColumns(){
144+
const w = grid.clientWidth;
145+
const cols = w < 768 ? 2 : (w < 1280 ? 3 : 5);
146+
if(cols === columns && columnWidth) return;
147+
columns = cols;
148+
columnWidth = Math.floor((w - CONFIG.gutter*(columns-1)) / columns);
149+
colHeights = new Array(columns).fill(0);
150+
colLefts = [];
151+
for(let i=0;i<columns;i++){ colLefts[i] = i*(columnWidth + CONFIG.gutter); }
152+
}
153+
function placeItem(el){
154+
el.style.width = columnWidth + 'px';
155+
el.style.position = 'absolute';
156+
const h = el.offsetHeight;
157+
let idx = 0; let min = colHeights[0];
158+
for(let i=1;i<columns;i++){ if(colHeights[i] < min){ min = colHeights[i]; idx = i; } }
159+
el.style.transform = 'translate('+colLefts[idx]+'px,'+min+'px)';
160+
colHeights[idx] = min + h + CONFIG.gutter;
161+
grid.style.height = Math.max.apply(null,colHeights) + 'px';
162+
}
163+
function layoutNew(items){
164+
computeColumns();
165+
for(let i=0;i<items.length;i++){ placeItem(items[i]); }
166+
}
167+
function layoutAll(){
168+
computeColumns();
169+
colHeights = new Array(columns).fill(0);
170+
const items = Array.prototype.slice.call(grid.querySelectorAll('.grid-item'));
171+
for(let i=0;i<items.length;i++){ placeItem(items[i]); }
172+
}
173+
window.__imgLoaded = function(img){
174+
const item = img.closest('.grid-item');
175+
if(item){
176+
const cont = item.querySelector('.img-container');
177+
if(cont) cont.style.height = '';
178+
layoutAll();
179+
}
180+
};
181+
window.addEventListener('resize', function(){ layoutAll(); });
160182

161-
// --- 2. 生成图片数据 ---
162-
function createElements(count) {
163-
let elements = [];
164-
for (let i = 0; i < count; i++) {
183+
// --- 2. 生成图片元素(基于抓取结果) ---
184+
function buildElements(items) {
185+
const elements = [];
186+
for (let i = 0; i < items.length; i++) {
187+
const it = items[i] || {};
165188
const width = 600;
166-
const height = Math.floor(Math.random() * (800 - 400 + 1)) + 400; // 随机高度
167-
168-
// 随机选择源 (优先用 Picsum 和 Flickr 因为比较稳)
169-
const source = apiSources[Math.floor(Math.random() * 2)];
170-
const url = source.fn(width, height);
189+
const height = (it.width && it.height) ? Math.round(width * (it.height / it.width)) : Math.floor(Math.random() * (800 - 400 + 1)) + 400;
190+
const url = it.url;
191+
const api = it.source || 'unknown';
192+
const dim = (it.width && it.height) ? `${it.width}x${it.height}` : `${width}x${height}`;
171193

172194
const div = document.createElement('div');
173195
div.className = 'grid-item';
174196
div.innerHTML = `
175-
<div class="img-container relative rounded-xl overflow-hidden bg-gray-800 cursor-pointer group">
197+
<div class="img-container relative rounded-xl overflow-hidden bg-gray-800 cursor-pointer group" style="height:${height}px">
176198
<div class="skeleton absolute inset-0 z-0"></div>
177199
<img src="${url}"
178200
class="relative z-10 w-full block opacity-0 transition-opacity duration-700"
179201
loading="lazy"
180-
data-api="${source.name}"
181-
data-dim="${width}x${height}"
182-
onload="this.style.opacity=1; this.previousElementSibling.style.display='none';"
202+
data-api="${api}"
203+
data-dim="${dim}"
204+
onload="this.style.opacity=1; this.previousElementSibling.style.display='none'; if(window.__imgLoaded) __imgLoaded(this);"
183205
onerror="this.parentElement.parentElement.style.display='none'"
184206
>
185207
<div class="absolute inset-0 bg-black/50 opacity-0 group-hover:opacity-100 transition-opacity duration-300 z-20 flex items-center justify-center">
@@ -193,46 +215,36 @@ <h1 class="text-xl font-bold tracking-widest">NEXUS<span class="text-neon">FLOW<
193215
}
194216

195217
// --- 3. 加载逻辑 ---
196-
function loadImages() {
218+
async function loadImages() {
197219
if (isLoading) return;
198220
isLoading = true;
199-
200-
// 显示 Loading
201221
gsap.to('#loader', { opacity: 1, duration: 0.2 });
202-
document.getElementById('status-indicator').innerText = "DOWNLOADING...";
222+
document.getElementById('status-indicator').innerText = "FETCHING WALLPAPERS...";
223+
224+
try {
225+
const orientation = (window.innerWidth > window.innerHeight) ? 'landscape' : 'portrait';
226+
const params = new URLSearchParams(location.search);
227+
const query = params.get('q') || '';
228+
const items = await window.fetchWallpapers({ count: CONFIG.batchSize, orientation, query, sources: ['unsplash','picsum'] });
229+
const newElems = buildElements(items);
203230

204-
// 模拟一点点延迟,让动画更自然
205-
setTimeout(() => {
206-
const newElems = createElements(CONFIG.batchSize);
207-
208-
// 1. 先把元素加入 DOM
209231
const fragment = document.createDocumentFragment();
210232
newElems.forEach(el => fragment.appendChild(el));
211233
grid.appendChild(fragment);
212-
213-
// 2. 追加给 Masonry
214-
msnry.appended(newElems);
215-
216-
// 3. 等待这批图片下载完成(或者失败)再重新布局
217-
// 这是一个关键点:imagesLoaded 确保图片有高度了再布局,防止重叠
218-
imagesLoaded(grid, function() {
219-
msnry.layout();
220-
221-
// 4. GSAP 入场动画
222-
gsap.to(newElems, {
223-
opacity: 1,
224-
y: 0,
225-
duration: 0.8,
226-
stagger: 0.05,
227-
ease: "power2.out",
228-
onComplete: () => {
229-
isLoading = false;
230-
gsap.to('#loader', { opacity: 0, duration: 0.2 });
231-
document.getElementById('status-indicator').innerText = "SYSTEM READY";
232-
}
233-
});
234-
});
235-
}, 500);
234+
layoutNew(newElems);
235+
gsap.fromTo(newElems,
236+
{ opacity: 0 },
237+
{ opacity: 1, duration: 0.8, stagger: 0.05, ease: "power2.out", onComplete: () => {
238+
isLoading = false;
239+
gsap.to('#loader', { opacity: 0, duration: 0.2 });
240+
document.getElementById('status-indicator').innerText = "SYSTEM READY";
241+
}}
242+
);
243+
} catch (e) {
244+
isLoading = false;
245+
gsap.to('#loader', { opacity: 0, duration: 0.2 });
246+
document.getElementById('status-indicator').innerText = "NETWORK ERROR";
247+
}
236248
}
237249

238250
// --- 4. 无限滚动 (IntersectionObserver) ---

pages/wallpaper.js

Lines changed: 28 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

参考黑洞.txt

Whitespace-only changes.

0 commit comments

Comments
 (0)