navmini/weapp/pages/index/index.js
eric 518410edd0 feat: 游民导航 H5、微信小程序与小红书小工具
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-27 12:15:00 -05:00

215 lines
5.6 KiB
JavaScript

const nav = require("../../data/links.json");
function countLinks(cat) {
let n = 0;
const groups = cat.groups || [];
for (let i = 0; i < groups.length; i++) {
n += (groups[i].links || []).length;
}
return n;
}
function withCounts(categories) {
return (categories || []).map((c) =>
Object.assign({}, c, { linkCount: countLinks(c) })
);
}
Page({
data: {
brand: nav.brand || "游民导航",
tagline: nav.tagline || "",
footer: nav.footer || "",
brandIcon: nav.brandIcon || "/icons/_brand.webp",
categories: withCounts(nav.categories),
activeId: (nav.categories && nav.categories[0] && nav.categories[0].id) || "",
activeTitle:
(nav.categories && nav.categories[0] && nav.categories[0].title) || "",
theme: "light",
drawerOpen: false,
showTop: false,
toast: "",
statusBarHeight: 20,
navBarHeight: 44,
sheetOpen: false,
sheetLink: null,
},
_jumping: false,
_sectionTops: [],
_toastTimer: null,
onLoad() {
const sys = wx.getWindowInfo ? wx.getWindowInfo() : wx.getSystemInfoSync();
const statusBarHeight = sys.statusBarHeight || 20;
const menu = wx.getMenuButtonBoundingClientRect
? wx.getMenuButtonBoundingClientRect()
: null;
let navBarHeight = 44;
if (menu && menu.height) {
navBarHeight = (menu.top - statusBarHeight) * 2 + menu.height;
}
const app = getApp();
const theme = (app && app.globalData && app.globalData.theme) || "light";
this.setData({
statusBarHeight,
navBarHeight,
theme,
});
this._applyTheme(theme);
},
onReady() {
wx.nextTick(() => this._measureSections());
},
onShow() {
this._applyTheme(this.data.theme);
},
onPageScroll(e) {
const scrollTop = e.scrollTop || 0;
const showTop = scrollTop > 480;
if (showTop !== this.data.showTop) {
this.setData({ showTop });
}
if (this._jumping || !this._sectionTops.length) return;
const marker = scrollTop + this.data.statusBarHeight + this.data.navBarHeight + 24;
let current = this._sectionTops[0].id;
for (let i = 0; i < this._sectionTops.length; i++) {
if (this._sectionTops[i].top <= marker) current = this._sectionTops[i].id;
else break;
}
if (current !== this.data.activeId) {
const cat = this.data.categories.find((c) => c.id === current);
this.setData({
activeId: current,
activeTitle: (cat && cat.title) || "",
});
}
},
_measureSections() {
const query = wx.createSelectorQuery();
query.selectAll(".cat-panel").boundingClientRect();
query.selectViewport().scrollOffset();
query.exec((res) => {
const rects = (res && res[0]) || [];
const scroll = (res && res[1]) || { scrollTop: 0 };
this._sectionTops = rects.map((r) => ({
id: (r.id || "").replace(/^cat-/, ""),
top: (r.top || 0) + (scroll.scrollTop || 0),
}));
});
},
_applyTheme(theme) {
const dark = theme === "dark";
wx.setNavigationBarColor({
frontColor: dark ? "#ffffff" : "#000000",
backgroundColor: dark ? "#0a0f14" : "#e9eef4",
animation: { duration: 200, timingFunc: "easeIn" },
});
wx.setBackgroundColor({
backgroundColor: dark ? "#0a0f14" : "#e9eef4",
backgroundColorTop: dark ? "#0a0f14" : "#e9eef4",
backgroundColorBottom: dark ? "#0a0f14" : "#e9eef4",
});
},
openDrawer() {
this.setData({ drawerOpen: true });
},
closeDrawer() {
this.setData({ drawerOpen: false });
},
noop() {},
toggleTheme() {
const theme = this.data.theme === "dark" ? "light" : "dark";
this.setData({ theme });
try {
wx.setStorageSync("navmini-theme", theme);
} catch (e) {
/* ignore */
}
const app = getApp();
if (app && app.globalData) app.globalData.theme = theme;
this._applyTheme(theme);
},
onSelectCategory(e) {
const id = e.currentTarget.dataset.id;
if (!id) return;
const cat = this.data.categories.find((c) => c.id === id);
this.setData({
drawerOpen: false,
activeId: id,
activeTitle: (cat && cat.title) || "",
});
this._jumping = true;
wx.pageScrollTo({
selector: `#cat-${id}`,
duration: 320,
offsetTop: -(this.data.statusBarHeight + this.data.navBarHeight + 8),
complete: () => {
setTimeout(() => {
this._jumping = false;
this._measureSections();
}, 360);
},
});
},
onTapLink(e) {
const { id, catid, groupid } = e.currentTarget.dataset;
let link = null;
const cat = this.data.categories.find((c) => c.id === catid);
if (cat) {
const group = (cat.groups || []).find((g) => g.id === groupid);
if (group) link = (group.links || []).find((l) => l.id === id);
}
if (!link || !link.href) {
this._showToast("无效链接");
return;
}
this.setData({ sheetOpen: true, sheetLink: link });
},
closeSheet() {
this.setData({ sheetOpen: false, sheetLink: null });
},
copySheetUrl() {
const link = this.data.sheetLink;
if (!link || !link.href) return;
wx.setClipboardData({
data: link.href,
success: () => {
this._showToast("已复制,请到浏览器打开");
},
fail: () => {
this._showToast("复制失败");
},
});
},
backTop() {
wx.pageScrollTo({ scrollTop: 0, duration: 300 });
},
_showToast(msg) {
if (this._toastTimer) clearTimeout(this._toastTimer);
this.setData({ toast: msg });
this._toastTimer = setTimeout(() => {
this.setData({ toast: "" });
this._toastTimer = null;
}, 1800);
},
});