码桶

发现社区成员的开源项目

开心 / 公开

版本历史

3 次提交

提交详情

b0e33fe
提交编号b0e33fe3480a7a8d577d61f8ca3308220fe60713
提交作者开心<codebucket@localhost>
提交时间2026-07-29 13:05:17 +0800
更新说明更新项目文件

文件变更 51 个文件

文件新增删除
README.md+398-1
ajax.php+396-0
assets/cache/.gitkeep+0-0
assets/css/admin-fix.css+130-0
assets/css/houtai.css+354-0
assets/css/style.css+1279-0
assets/css/style.min.css+1-0
assets/img/default-avatar.svg+1-0
assets/js/app.min.js+1460-0
assets/js/app.v2.js+1512-0
assets/js/houtai.js+54-0
assets/lib/fancybox/fancybox.css+1-0
assets/lib/fancybox/fancybox.umd.min.js+7-0
assets/lib/prism/prism-bash.min.js+1-0
assets/lib/prism/prism-c.min.js+1-0
assets/lib/prism/prism-cpp.min.js+1-0
assets/lib/prism/prism-css.min.js+1-0
assets/lib/prism/prism-go.min.js+1-0
assets/lib/prism/prism-html.min.js+1-0
assets/lib/prism/prism-java.min.js+1-0
assets/lib/prism/prism-javascript.min.js+1-0
assets/lib/prism/prism-json.min.js+1-0
assets/lib/prism/prism-kotlin.min.js+1-0
assets/lib/prism/prism-line-numbers.min.css+1-0
assets/lib/prism/prism-line-numbers.min.js+1-0
assets/lib/prism/prism-markup.min.js+1-0
assets/lib/prism/prism-php.min.js+1-0
assets/lib/prism/prism-python.min.js+1-0
assets/lib/prism/prism-ruby.min.js+1-0
assets/lib/prism/prism-rust.min.js+1-0
assets/lib/prism/prism-sql.min.js+1-0
assets/lib/prism/prism-swift.min.js+1-0
assets/lib/prism/prism-typescript.min.js+1-0
assets/lib/prism/prism.css+1-0
assets/lib/prism/prism.min.js+16-0
assets/lib/qrcode/qrcode.min.js+8-0
comments.php+13-0
footer.php+100-0
functions.php+495-0
header.php+189-0
img-proxy.php+169-0
index.php+71-0
lib/Meting.php+1535-0
lib/ip2region/xdb/Searcher.class.php+573-0
music-proxy.php+65-0
page-about.php+125-0
page-archive.php+134-0
page-links.php+76-0
page.php+21-0
post.php+65-0
setting.php+162-0

文件差异 逐行查看本次提交的修改

README.md+398-1
@@ -1 +1,398 @@
1-# kxpyq
1+# Pyq 主题 — 详细功能总结与技术文档
2+
3+> **主题名称:** Pyq
4+> **作者:** 清酒
5+> **版本:** 1.0.0 (2026-06-28)
6+> **适配程序:** Typecho 1.3.0
7+> **运行环境:** PHP 8.2 + MySQL 5.7
8+> **站点地址:** https://p.qu.pw/
9+> **主题目录:** `/www/wwwroot/p.qu.pw/usr/themes/pyq/`
10+
11+---
12+
13+## 一、主题概述
14+
15+Pyq 是一款仿朋友圈风格的 Typecho 主题,以说说(短文)为核心,支持图文、音乐、视频、链接等多种内容形式。移动端优先设计,支持深色模式、PJAX 无刷新导航、LRC 歌词滚动等高级功能。
16+
17+参考主题:wutoutu(同目录下),在此基础上进行了大量功能增强和 UI 优化。
18+
19+---
20+
21+## 二、文件结构
22+
23+```
24+pyq/
25+├── index.php # 首页模板(说说列表 + 分页 + AJAX加载更多)
26+├── post.php # 文章详情页(单篇说说 + 评论区)
27+├── page.php # 通用页面模板
28+├── page-about.php # 关于页面(社交账号弹窗)
29+├── page-links.php # 友链页面
30+├── page-archive.php # 归档页面(按月分组)
31+├── header.php # 公共头部(导航栏 + 封面 + 公告 + 音乐播放器)
32+├── footer.php # 公共底部(弹窗公告 + 返回顶部 + JS加载)
33+├── comments.php # 评论模板
34+├── functions.php # 主题函数(自定义字段 + 工具函数)
35+├── setting.php # 后台设置页(Tab式界面)
36+├── ajax.php # AJAX接口(加载更多 + 评论提交 + 点赞)
37+├── music-proxy.php # 音乐代理(本地Meting库 + 流式传输)
38+├── img-proxy.php # 图片代理(防盗链处理)
39+├── assets/
40+│ ├── css/
41+│ │ ├── style.css # 前台主样式(1193行)
42+│ │ ├── houtai.css # 后台设置页样式(354行)
43+│ │ └── admin-fix.css # 后台全局修复CSS(130行)
44+│ ├── js/
45+│ │ ├── app.js # 前台主逻辑(1250行)
46+│ │ └── houtai.js # 后台设置页逻辑(54行)
47+│ └── img/ # 主题图片资源
48+├── lib/
49+│ └── Meting.php # Metowolf Meting 音乐API库
50+└── static/
51+ └── prism/ # Prism.js 代码高亮(22个文件,16种语言)
52+```
53+
54+**总代码量:** 5266 行
55+
56+---
57+
58+## 三、功能特性
59+
60+### 3.1 内容类型
61+
62+| 类型 | 自定义字段 | 说明 |
63+|------|-----------|------|
64+| 图文 | `images`(多行文本) | 多图URL,每行一张,支持懒加载 |
65+| 视频 | `video_url`(单行文本) | 视频链接,支持 mp4/embed |
66+| 音乐 | `music_url` + `music_name` + `music_artist` + `music_cover` + `music_lrc` | 音乐卡片,支持封面+歌词 |
67+| 链接 | `link_url` + `link_title` + `link_desc` + `link_thumb` | 外部链接卡片预览 |
68+| 位置 | `location`(单行文本) | 显示位置信息 |
69+| 置顶 | `is_top`(单选:是/否) | 置顶文章 |
70+
71+### 3.2 音乐系统
72+
73+#### 顶部播放器
74+- 导航栏集成迷你播放器(播放/暂停 + 歌名滚动)
75+- 支持两种音源:
76+ - `bgm_url`:直接 MP3 链接(优先)
77+ - `netease_id`:网易云歌曲ID,通过本地 Meting 库代理获取
78+- 音乐代理 `music-proxy.php`:流式传输 + Range 分块请求支持
79+
80+#### 音乐卡片(说说内嵌)
81+- 80px 高度卡片,封面背景 + 歌曲名 + 歌手 + 播放按钮
82+- 底部进度条(3px,hover 6px),支持拖动 seek
83+- LRC 歌词滚动:
84+ - 支持标准 LRC 格式(`[00:12.34]歌词`)
85+ - 支持网易云 JSON 格式(`{"t":0,"c":[{"tx":"歌词"}]}`)
86+ - 歌词区在卡片下方展开,背景使用封面模糊图
87+ - 当前行高亮(白色 15px + 发光阴影)
88+ - `requestAnimationFrame` 同步滚动,使用 `scrollTo` 避免页面抖动
89+ - 展开/收起按钮,可手动控制
90+
91+### 3.3 评论系统
92+
93+- AJAX 无刷新提交评论
94+- 必填昵称 + 邮箱(邮箱格式校验)
95+- 评论 @回复 功能(点击回复按钮自动填充)
96+- 评论邮件通知:
97+ - 直接调用 CommentNotifier 插件的 `refinishComment` 方法
98+ - 绕过异步模式(`yibu=1`),确保邮件即时发送
99+ - 修复 `ownerId` 为 0 的问题,从 `typecho_contents` 查询文章作者
100+- 评论树形渲染(`pyq_render_comments_tree`)
101+
102+### 3.4 交互功能
103+
104+- **点赞:** AJAX 点赞/取消,实时更新按钮状态和点赞列表
105+- **分享:** 8 按钮弹窗(2×4 网格)— 微信/微博/QQ/复制链接/带标题复制/更多
106+- **返回顶部:** 滚动 300px 后显示,平滑滚动
107+- **图片灯箱:** FancyBox 集成,点击图片放大查看
108+- **懒加载:** IntersectionObserver 图片懒加载
109+- **加载更多:** 滚动到底部自动加载下一页(AJAX)
110+
111+### 3.5 PJAX 无刷新导航
112+
113+- 全站 PJAX 实现,音乐播放不中断
114+- `XMLHttpRequest` + `DOMParser` 解析新页面
115+- `history.pushState` / `popstate` 浏览器前进后退支持
116+- 换页后自动重新初始化:FancyBox、Prism.js、懒加载、搜索、加载更多
117+- 内容区域目标:`#pyq-feed`
118+
119+### 3.6 深色模式
120+
121+- 跟随系统 `prefers-color-scheme` 自动切换
122+- CSS 变量体系(`--bg`, `--card`, `--text`, `--text2`, `--text3`, `--border` 等)
123+- 所有组件完整适配深色/浅色
124+
125+### 3.7 代码高亮
126+
127+- Prism.js 集成(16 种语言)
128+- 暗色主题 + 行号 + 一键复制按钮
129+- `pyq_parse_code()` 函数处理代码块
130+
131+---
132+
133+## 四、后台设置
134+
135+### 4.1 设置界面
136+
137+Tab 式布局(5 个标签页):
138+
139+| 标签 | 内容 |
140+|------|------|
141+| 基础设置 | 头像URL、封面图URL、封面高度、用户名、个性签名、ICP备案、说说分类slug、静态资源URL |
142+| 音乐设置 | 背景音乐URL、网易云歌曲ID |
143+| 社交菜单 | GitHub/微博/微信/QQ 链接 + 菜单项配置 |
144+| 功能设置 | 公告文字、公告背景色(色盘选择)、Gravatar源选择、弹窗公告 |
145+| 高级设置 | 自定义CSS/JS 代码注入 |
146+
147+### 4.2 设置备份
148+
149+- 一键备份当前所有设置
150+- 列出历史备份,支持一键恢复/删除
151+- 备份存储在 `typecho_options` 表中
152+
153+### 4.3 自定义字段
154+
155+文章编辑页自定义字段支持:
156+- textarea 高度优化(36px 起,可拖拽调整)
157+- 文字描述改为 placeholder(`$e->input->setAttribute`)
158+- Radio 按钮置顶选择(is_top)
159+- 所有字段支持 JS 拖拽调整宽度(text input)
160+
161+---
162+
163+## 五、页面模板
164+
165+### 5.1 关于页面 (`page-about.php`)
166+
167+- 社交账号展示(QQ/微信/GitHub/微博)
168+- 点击弹窗显示账号信息(QQ 弹窗、微信弹窗)
169+- 复制账号到剪贴板
170+- 弹窗函数在 `app.js` 中定义(PJAX 兼容)
171+
172+### 5.2 友链页面 (`page-links.php`)
173+
174+- 配合links插件使用
175+- 友链列表展示
176+- 卡片式布局
177+
178+### 5.3 归档页面 (`page-archive.php`)
179+
180+- 按年月分组的文章列表
181+- 链接格式:`/archives/slug.html`
182+
183+---
184+
185+## 六、技术实现细节
186+
187+### 6.1 IIFE 架构
188+
189+`app.js` 使用 IIFE(立即执行函数表达式)封装,所有功能通过 `pyq.xxx` 暴露到全局:
190+
191+```javascript
192+;(function(){
193+ // 内部变量
194+ var pyq = window.pyq = {};
195+ // 所有功能定义...
196+ pyq.playCardMusic = function(btn){ ... };
197+ pyq.parseLrc = function(text){ ... };
198+ // ...
199+})();
200+```
201+
202+**关键教训:** IIFE 闭合 `})();` 必须在所有 `pyq.xxx` 定义之后,否则后续代码引用 `pyq` 会 ReferenceError。
203+
204+### 6.2 音乐卡片 HTML 结构
205+
206+```html
207+<div class="pyq-music-wrap" data-bg="封面URL">
208+ <div class="pyq-music-card" data-src="音频URL" data-name="歌名" data-lrc="base64歌词">
209+ <div class="pyq-music-card-bg" style="background-image:url(...)"></div>
210+ <div class="pyq-music-card-left"><img src="封面"></div>
211+ <div class="pyq-music-card-right">
212+ <div class="pyq-music-card-info">
213+ <div class="pyq-music-card-title">歌名</div>
214+ <div class="pyq-music-card-artist">歌手</div>
215+ </div>
216+ <div class="pyq-music-card-play" onclick="pyq.playCardMusic(this)">▶</div>
217+ </div>
218+ <div class="pyq-music-progress" onmousedown="pyq.seekMusic(event,this)">
219+ <div class="pyq-music-progress-bar"></div>
220+ <div class="pyq-music-progress-dot"></div>
221+ </div>
222+ </div>
223+ <div class="pyq-lrc-bar" onclick="pyq.toggleLrc(this)">歌词 ▼</div>
224+ <div class="pyq-music-lrc">
225+ <div class="pyq-lrc-bg" style="background-image:url(...)"></div>
226+ <div class="pyq-lrc-overlay"></div>
227+ <div class="pyq-lrc-lines"></div>
228+ </div>
229+</div>
230+```
231+
232+### 6.3 LRC 歌词解析
233+
234+支持两种格式:
235+
236+**标准 LRC:**
237+```
238+[00:12.34]歌词第一行
239+[00:15.67]歌词第二行
240+```
241+
242+**网易云 JSON:**
243+```json
244+[{"t":0,"c":[{"tx":"作词: "},{"tx":"某某"}]},{"t":4000,"c":[{"tx":"歌词"}]}]
245+```
246+
247+解析流程:
248+1. 检测首字符是否为 `{` 或 `[`
249+2. JSON 格式:解析数组,提取 `t`(毫秒)和 `c[].tx`(文本)
250+3. LRC 格式:正则 `/[(\d{1,2}):(\d{2})(?:\.(\d{1,3}))?](.*)/g` 匹配
251+4. 按时间排序
252+
253+### 6.4 歌词同步机制
254+
255+- `requestAnimationFrame` 高频循环(60fps)
256+- 遍历已排序的歌词数组,找到当前时间对应的行
257+- 高亮当前行(`.active` class)
258+- `scrollTo` 滚动容器到当前行位置(不用 `scrollIntoView`,避免页面抖动)
259+- 暂停时停止循环,恢复时重新启动
260+
261+### 6.5 进度条拖动
262+
263+- `mousedown/touchstart` 记录起始位置
264+- `mousemove/touchmove` 实时计算百分比,更新 `audio.currentTime`
265+- `mouseup/touchend` 清理事件监听
266+- `getBoundingClientRect` 计算相对位置
267+- 拖动中添加 `.dragging` class(白点常显 + 进度条变高)
268+
269+### 6.6 邮件通知修复
270+
271+三层问题修复:
272+
273+1. **插件未初始化:** `ajax.php` 需调用 `Plugin::init()` 初始化插件系统
274+2. **ownerId 为 0:** `typecho_comments.ownerId` 全为 0,需从 `typecho_contents` 查 `authorId` 补全
275+3. **异步模式失效:** CommentNotifier 的 `yibu=1` 模式在 AJAX handler 中不触发,直接调用 `Plugin::refinishComment($feedback)` 绕过
276+
277+### 6.7 后台 CSS 注入
278+
279+通过 `admin/header.php` 直接注入 `admin-fix.css`,修复:
280+- select 下拉框样式(移动端 font-size 16px 防缩放)
281+- textarea 可拖拽(覆盖 Typecho 的 `resize: none`)
282+- 编辑器容器居中(覆盖 `.row { width: 100vw }`)
283+- 移动端自定义字段、提交按钮全宽适配
284+
285+---
286+
287+## 七、CSS 变量
288+
289+```css
290+:root {
291+ --bg: #f0f0f0; /* 页面背景 */
292+ --card: #fff; /* 卡片背景 */
293+ --card2: #f5f5f5; /* 次级卡片 */
294+ --text: #333; /* 主文字 */
295+ --text2: #666; /* 次级文字 */
296+ --text3: #999; /* 辅助文字 */
297+ --border: #eee; /* 边框 */
298+ --accent: #07c160; /* 强调色(微信绿) */
299+ --max-w: 680px; /* 最大宽度 */
300+ --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
301+}
302+
303+.darkmode {
304+ --bg: #1a1a1a;
305+ --card: #242424;
306+ --card2: #2a2a2a;
307+ --text: #e5e5e5;
308+ --text2: #aaa;
309+ --text3: #777;
310+ --border: #333;
311+}
312+```
313+
314+---
315+
316+## 八、数据库交互
317+
318+### 8.1 表结构
319+
320+- `typecho_contents`:文章内容
321+- `typecho_fields`:自定义字段(`name` + `str_value` + `cid`)
322+- `typecho_comments`:评论
323+- `typecho_users`:用户
324+- `typecho_options`:设置项
325+
326+### 8.2 关键查询
327+
328+```sql
329+-- 获取自定义字段
330+SELECT name, str_value FROM typecho_fields WHERE cid = ?
331+
332+-- 获取评论(带用户信息)
333+SELECT c.*, u.screenName FROM typecho_comments c
334+LEFT JOIN typecho_users u ON c.authorId = u.uid
335+WHERE c.cid = ? ORDER BY c.created ASC
336+
337+-- 文章作者查询(修复 ownerId=0 问题)
338+SELECT authorId FROM typecho_contents WHERE cid = ?
339+```
340+
341+---
342+
343+## 九、插件依赖
344+
345+| 插件 | 状态 | 用途 |
346+|------|------|------|
347+| CommentNotifier | ✅ 已激活 | 评论邮件通知 |
348+| Links | ✅ 已激活 | 友链管理 |
349+| ArticlePoster | ⚠️ 状态未知 | 文章海报生成 |
350+
351+---
352+
353+## 十、备份清单
354+
355+| 备份名 | 时间 | 说明 |
356+|--------|------|------|
357+| pyq_backup_20260627_210104 | 06-27 21:01 | 最初完整备份 |
358+| pyq_backup_20260628_123511 | 06-28 12:35 | Tab式设置界面完成后 |
359+| pyq_backup_20260628_141400 | 06-28 14:14 | LRC功能尝试前 |
360+| pyq_backup_20260628_153600 | 06-28 15:36 | LRC回滚后 |
361+| pyq_backup_20260628_163947 | 06-28 16:39 | 代码清理后 |
362+| pyq_backup_20260628_173800 | 06-28 17:38 | 移动端优化后 |
363+| pyq_backup_20260628_181600 | 06-28 18:16 | LRC首轮修复后 |
364+| pyq_backup_20260628_184200 | 06-28 18:42 | LRC二轮修复后 |
365+| pyq_backup_20260628_185100 | 06-28 18:51 | 进度条前 |
366+| pyq_backup_20260628_190200 | 06-28 19:02 | 最新 |
367+
368+---
369+
370+## 十一、踩坑记录(关键教训)
371+
372+1. **Typecho `.row` 默认 `width: 100vw`** — 导致编辑器容器溢出,需覆盖为 `width: 100%`
373+2. **Typecho `setAttribute()` 设在 `<li>` 上** — 需用 `$e->input->setAttribute()` 设在 `<input>` 上
374+3. **IIFE 闭合位置错误** — `})();` 必须在所有 `pyq.xxx` 定义之后
375+4. **`display:none` 的父容器** — 子元素的 `display:flex` 无效,必须同时检查父容器
376+5. **PJAX 内联 script 不执行** — `innerHTML` 注入的 `<script>` 不会执行,函数必须放外部 JS
377+6. **`height:0;overflow:hidden` 的容器** — 内部元素永远不可交互,按钮必须放外面
378+7. **CSS 变量不能用于伪元素 `background-image`** — 跨浏览器不兼容,用真实 DOM 更可靠
379+8. **`scrollIntoView` 带动页面滚动** — 容器高度动画时使用 `scrollTo` 代替
380+9. **单引号里 `\n` 是字面量** — 不是换行,需用双引号
381+10. **Typecho 插件钩子系统** — 命名空间必须是 `TypechoPlugin\PluginName\ClassName`,手动 SQL 激活不会运行构造函数
382+
383+---
384+
385+## 十二、性能优化
386+
387+- 图片懒加载(IntersectionObserver)
388+- PJAX 无刷新(减少整页重载)
389+- CSS `will-change` 用于动画元素
390+- `requestAnimationFrame` 用于高频更新(歌词同步、进度条)
391+- 音乐代理流式传输(不缓存完整文件)
392+- Prism.js 按需加载(仅代码块页面)
393+
394+---
395+
396+_文档生成时间:2026-06-28 19:02_
397+_主题总代码量:5266 行_
398+_备份总数:10 个_