From 22da441688e48256efa0854c144a573ad315f1b8 Mon Sep 17 00:00:00 2001
From: zhangminghao <2275599059@qq.com>
Date: Fri, 5 Sep 2025 15:25:26 +0800
Subject: [PATCH] =?UTF-8?q?=E8=8B=8F=E9=9D=92=E5=A3=B3=20=E5=8F=8A?=
=?UTF-8?q?=E8=AF=AD=E9=9F=B3=E6=92=AD=E6=8A=A5=20josn?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
App.vue | 3 +-
bmzm/chapter1/index.vue | 372 ++--
bmzm/chapter2/index.vue | 5 +-
bmzm/chapter3/index.vue | 5 +-
bmzm/chapter4/index.vue | 5 +-
bmzm/chapter5/index.vue | 5 +-
bmzm/chapter6/index.vue | 5 +-
bmzm/chapter7/index.vue | 5 +-
bmzm/home/home.vue | 5 +-
components/AudioControl.vue | 289 +++
components/AudioControl使用文档.md | 155 ++
components/MusicControl.vue | 65 +-
components/SwipeToNext.vue | 2 +-
.../跨页面音频控制解决方案.md | 225 +++
components/音频背景音乐交互说明.md | 144 ++
main.js | 1 +
pages.json | 7 -
pages/index/readingBody.vue | 16 +-
pig/chapter1/chapter1.vue | 5 +-
pig/chapter2/chapter2.vue | 5 +-
pig/chapter3/chapter3.vue | 5 +-
pig/chapter4/chapter4.vue | 5 +-
pig/home/home.vue | 1749 ++++++++---------
static/js/CommonFunction.js | 96 +-
taozi/chapter1/chapter1.vue | 5 +-
taozi/chapter2/chapter2.vue | 5 +-
taozi/chapter3/chapter3.vue | 5 +-
taozi/chapter4/chapter4.vue | 5 +-
taozi/home/home.vue | 5 +-
utils/globalAudioManager.js | 92 +
xqk/chapter1/index.vue | 206 +-
xqk/chapter2/index.vue | 55 +-
xqk/chapter3/index.vue | 154 +-
xqk/chapter4/index.vue | 164 +-
xqk/chapter5/index.vue | 74 +-
xqk/chapter6/index.vue | 138 +-
xqk/chapter7/index.vue | 143 --
xqk/chapter8/index.vue | 75 -
xqk/components/NavMenu.vue | 6 +-
xqk/home/home.vue | 52 +-
xrcc/chapter1/index.vue | 16 +-
xrcc/chapter2/index.vue | 5 +-
xrcc/chapter3/index.vue | 6 +-
xrcc/chapter4/index.vue | 6 +-
xrcc/chapter5/index.vue | 6 +-
xrcc/chapter6/index.vue | 6 +-
xrcc/chapter7/index.vue | 6 +-
xrcc/chapter8/index.vue | 6 +-
xrcc/home/home.vue | 31 +-
xxdf/chapter1/cover1.vue | 5 +-
xxdf/chapter1/detail1.vue | 4 +-
xxdf/chapter1/detail2.vue | 5 +-
xxdf/chapter1/detail3.vue | 5 +-
xxdf/chapter1/detail4.vue | 5 +-
xxdf/chapter1/detail5.vue | 5 +-
xxdf/chapter2/cover.vue | 5 +-
xxdf/chapter3/cover.vue | 5 +-
xxdf/chapter4/cover.vue | 6 +-
xxdf/home/home.vue | 5 +-
59 files changed, 2758 insertions(+), 1743 deletions(-)
create mode 100644 components/AudioControl.vue
create mode 100644 components/AudioControl使用文档.md
create mode 100644 components/跨页面音频控制解决方案.md
create mode 100644 components/音频背景音乐交互说明.md
create mode 100644 utils/globalAudioManager.js
delete mode 100644 xqk/chapter7/index.vue
delete mode 100644 xqk/chapter8/index.vue
diff --git a/App.vue b/App.vue
index 2e0616a..c8f52ac 100644
--- a/App.vue
+++ b/App.vue
@@ -5,7 +5,8 @@
randomImages: [],
bgMusic: null,
isMusicPlaying: false,
- musicSrc: 'https://static.ticket.sz-trip.com/epicSoul/EpicSouls.mp3'
+ musicSrc: 'https://static.ticket.sz-trip.com/epicSoul/EpicSouls.mp3',
+ currentAudio: null // 全局音频实例
},
onLaunch: function() {
console.warn('当前组件仅支持 uni_modules 目录结构 ,请升级 HBuilderX 到 3.1.0 版本以上!')
diff --git a/bmzm/chapter1/index.vue b/bmzm/chapter1/index.vue
index ca9a618..388a729 100644
--- a/bmzm/chapter1/index.vue
+++ b/bmzm/chapter1/index.vue
@@ -1,147 +1,263 @@
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
+
-
+
-
-
-
+
+
+
-
+
+
\ No newline at end of file
diff --git a/bmzm/chapter2/index.vue b/bmzm/chapter2/index.vue
index 15c6f29..de98934 100644
--- a/bmzm/chapter2/index.vue
+++ b/bmzm/chapter2/index.vue
@@ -10,16 +10,19 @@
+
+
+
\ No newline at end of file
diff --git a/components/AudioControl使用文档.md b/components/AudioControl使用文档.md
new file mode 100644
index 0000000..4b2ed0d
--- /dev/null
+++ b/components/AudioControl使用文档.md
@@ -0,0 +1,155 @@
+# AudioControl 音频控制组件使用文档
+
+## 组件功能
+- 在父组件右上角显示音频控制图标
+- 点击图标播放指定音频,同时暂停背景音乐
+- 再次点击暂停音频,恢复背景音乐
+- 音频播放结束后自动恢复背景音乐
+
+## 组件属性 (Props)
+
+| 属性名 | 类型 | 必填 | 默认值 | 说明 |
+|--------|------|------|--------|------|
+| audioSrc | String | 是 | - | 音频文件路径 |
+| visible | Boolean | 否 | true | 是否显示组件 |
+
+## 使用方法
+
+### 1. 在父组件中引入和注册组件
+
+```vue
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### 2. 使用项目中的showImg方法(推荐)
+
+如果你的音频文件也存储在项目服务器上,可以使用项目的showImg方法:
+
+```vue
+
+```
+
+### 3. 动态控制音频源
+
+你可以根据不同的页面或条件播放不同的音频:
+
+```vue
+
+```
+
+## 样式说明
+
+组件默认定位在父组件的右上角(top: 30rpx, right: 30rpx),如果需要调整位置,可以在父组件中覆盖样式:
+
+```vue
+
+```
+
+## 注意事项
+
+1. **父组件样式**:确保父组件设置了 `position: relative`,这样AudioControl组件才能正确定位
+2. **音频格式**:建议使用 mp3 格式的音频文件,兼容性最好
+3. **音频路径**:确保音频文件路径正确且可访问
+4. **背景音乐**:组件会自动处理与MusicControl组件的交互,无需额外配置
+
+## 图标说明
+
+- 🔊:音频未播放状态
+- 🎧:音频播放中状态,带有脉动动画效果
+
+## 事件处理
+
+组件内部已处理所有音频播放逻辑,包括:
+- 播放音频时自动暂停背景音乐
+- 暂停音频时自动恢复背景音乐
+- 音频播放结束时自动恢复背景音乐
+- 组件销毁时自动清理资源
+
+## 示例场景
+
+适用于以下场景:
+- 章节页面播放对应的音频解说
+- 展示页面播放介绍音频
+- 互动页面播放提示音频
+- 任何需要临时播放音频并暂停背景音乐的场景
\ No newline at end of file
diff --git a/components/MusicControl.vue b/components/MusicControl.vue
index 54b8986..ffb7bf4 100644
--- a/components/MusicControl.vue
+++ b/components/MusicControl.vue
@@ -11,24 +11,35 @@ export default {
name: 'MusicControl',
data() {
return {
- isPlaying: false
+ isPlaying: false,
+ isAudioPlaying: false // 记录音频播放状态
}
},
mounted() {
- console.log('初始化')
+ // console.log('初始化')
// 组件挂载时同步音乐状态
this.syncMusicState();
+ // 检查全局音频状态
+ this.checkGlobalAudioState();
+
// 添加定时器,每秒同步一次状态
this.timer = setInterval(() => {
this.syncMusicState();
+ this.checkGlobalAudioState();
}, 1000);
+
+ // 监听音频播放状态变化
+ uni.$on('audioPlaying', this.handleAudioStateChange);
},
beforeUnmount() {
// 组件卸载前清除定时器
if (this.timer) {
clearInterval(this.timer);
}
+
+ // 移除事件监听
+ uni.$off('audioPlaying', this.handleAudioStateChange);
},
methods: {
syncMusicState() {
@@ -41,19 +52,57 @@ export default {
toggleMusic() {
const app = getApp();
if (!app || !app.globalData || !app.globalData.bgMusic) {
- console.error('背景音乐未初始化');
+ // console.error('背景音乐未初始化');
return;
}
const bgMusic = app.globalData.bgMusic;
- console.log(bgMusic)
+ // console.log(bgMusic)
- // 直接基于当前组件的状态切换
- if (this.isPlaying) {
- bgMusic.pause();
+ // 先发送背景音乐切换事件,通知AudioControl组件(但不要让它恢复背景音乐)
+ if (this.isAudioPlaying) {
+ uni.$emit('backgroundMusicToggle');
+ // 等待一小段时间确保音频已暂停
+ setTimeout(() => {
+ // 直接基于当前组件的状态切换背景音乐
+ if (this.isPlaying) {
+ bgMusic.pause();
+ } else {
+ bgMusic.play();
+ }
+ }, 100);
} else {
- bgMusic.play();
+ // 没有音频在播放时,直接切换背景音乐
+ if (this.isPlaying) {
+ bgMusic.pause();
+ } else {
+ bgMusic.play();
+ }
+ }
+ },
+
+ // 处理音频状态变化
+ handleAudioStateChange(isAudioPlaying) {
+ this.isAudioPlaying = isAudioPlaying;
+ // console.log('音频状态变化:', isAudioPlaying);
+ },
+
+ // 检查全局音频状态
+ checkGlobalAudioState() {
+ try {
+ const app = getApp();
+ if (app && app.globalData && app.globalData.currentAudio) {
+ const globalAudio = app.globalData.currentAudio;
+ // 检查全局音频是否在播放
+ this.isAudioPlaying = !globalAudio.paused;
+ // console.log('检查到全局音频状态:', this.isAudioPlaying);
+ } else {
+ this.isAudioPlaying = false;
+ }
+ } catch (error) {
+ // console.error('检查全局音频状态失败:', error);
+ this.isAudioPlaying = false;
}
}
}
diff --git a/components/SwipeToNext.vue b/components/SwipeToNext.vue
index f918e49..3558f0b 100644
--- a/components/SwipeToNext.vue
+++ b/components/SwipeToNext.vue
@@ -34,7 +34,7 @@ export default {
// 提示文字内容
tipText: {
type: String,
- default: '上滑动进入下一章节'
+ default: '上滑进入下一章节'
},
// 滑动阈值(px)
swipeThreshold: {
diff --git a/components/跨页面音频控制解决方案.md b/components/跨页面音频控制解决方案.md
new file mode 100644
index 0000000..a32147a
--- /dev/null
+++ b/components/跨页面音频控制解决方案.md
@@ -0,0 +1,225 @@
+# 跨页面音频控制解决方案
+
+## 进一步优化:解决跨页面状态同步问题
+
+### 问题描述
+在跨页面场景下,当音频正在播放时跳转到新页面,新页面的MusicControl组件不知道有音频在播放,点击背景音乐按钮时会直接播放背景音乐,导致音频和背景音乐同时播放。
+
+### 解决方案
+
+#### 1. MusicControl组件增强检测
+```javascript
+// 在mounted生命周期中添加全局音频状态检测
+mounted() {
+ this.syncMusicState();
+ this.checkGlobalAudioState(); // 新增:检查全局音频状态
+
+ // 定时器也要检查全局音频状态
+ this.timer = setInterval(() => {
+ this.syncMusicState();
+ this.checkGlobalAudioState();
+ }, 1000);
+}
+
+// 新增方法:检查全局音频状态
+checkGlobalAudioState() {
+ const app = getApp();
+ if (app && app.globalData && app.globalData.currentAudio) {
+ const globalAudio = app.globalData.currentAudio;
+ this.isAudioPlaying = !globalAudio.paused;
+ } else {
+ this.isAudioPlaying = false;
+ }
+}
+```
+
+#### 2. 全局音频管理工具优化
+```javascript
+// 在音频状态变化时发送全局事件
+pauseCurrentAudio() {
+ const audio = this.getCurrentAudio();
+ if (audio && !audio.paused) {
+ audio.pause();
+ this.notifyAudioStateChange(false); // 通知状态变化
+ return true;
+ }
+ return false;
+}
+
+// 新增:通知音频状态变化
+notifyAudioStateChange(isPlaying) {
+ if (typeof uni !== 'undefined') {
+ uni.$emit('audioPlaying', isPlaying);
+ }
+}
+```
+
+### 修复后的交互流程
+```mermaid
+graph TD
+A[跨页面跳转] --> B[MusicControl组件加载]
+B --> C[检查全局音频状态]
+C --> D{有音频在播放?}
+D -->|是| E[设置isAudioPlaying=true]
+D -->|否| F[设置isAudioPlaying=false]
+E --> G[点击背景音乐按钮]
+F --> G
+G --> H{检查isAudioPlaying}
+H -->|有音频| I[先暂停音频再播放背景音乐]
+H -->|无音频| J[直接播放背景音乐]
+```
+
+## 问题描述
+
+AudioControl组件在页面跳转时会出现以下问题:
+1. 组件状态重置,图标显示不正确
+2. 音频实例丢失连接,但音频可能仍在播放
+3. 无法在其他页面控制正在播放的音频
+
+## 解决方案
+
+### 1. 全局音频实例管理
+
+在`App.vue`的`globalData`中添加`currentAudio`属性,用于保存当前的音频实例:
+
+```javascript
+globalData: {
+ // ... 其他属性
+ currentAudio: null // 全局音频实例
+}
+```
+
+### 2. AudioControl组件优化
+
+#### 状态同步机制
+- 组件挂载时检查全局音频状态
+- 复用已存在的音频实例(如果URL匹配)
+- 组件销毁时不销毁全局音频实例
+
+#### 核心方法改进
+```javascript
+// 检查全局音频状态
+checkGlobalAudioState() {
+ const app = getApp();
+ if (app && app.globalData && app.globalData.currentAudio) {
+ const globalAudio = app.globalData.currentAudio;
+ if (globalAudio.src === this.audioSrc) {
+ this.isAudioPlaying = !globalAudio.paused;
+ }
+ }
+}
+
+// 初始化音频时复用全局实例
+initAudio() {
+ const app = getApp();
+ if (app && app.globalData && app.globalData.currentAudio) {
+ if (app.globalData.currentAudio.src === this.audioSrc) {
+ // 复用现有实例
+ this.audioContext = app.globalData.currentAudio;
+ this.isAudioPlaying = !this.audioContext.paused;
+ return;
+ }
+ }
+ // 创建新实例...
+}
+```
+
+### 3. 全局音频管理工具
+
+创建了`utils/globalAudioManager.js`工具类,提供统一的音频控制接口:
+
+```javascript
+// 在任何页面或组件中使用
+uni.$globalAudio.pauseCurrentAudio(); // 暂停当前音频
+uni.$globalAudio.playCurrentAudio(); // 播放当前音频
+uni.$globalAudio.isAudioPlaying(); // 检查播放状态
+uni.$globalAudio.getCurrentAudioSrc(); // 获取当前音频源
+```
+
+## 使用示例
+
+### 在页面中控制音频
+
+```vue
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### 在其他页面检查音频状态
+
+```javascript
+// 在任何页面的onShow生命周期中
+onShow() {
+ // 检查是否有音频在播放
+ if (uni.$globalAudio.isAudioPlaying()) {
+ console.log('有音频正在播放:', uni.$globalAudio.getCurrentAudioSrc());
+ }
+}
+```
+
+## 技术优势
+
+### ✅ **状态持久化**
+- 音频实例在页面跳转时不会丢失
+- 组件状态能够正确同步全局音频状态
+
+### ✅ **跨页面控制**
+- 在任何页面都可以控制当前播放的音频
+- 提供统一的音频管理接口
+
+### ✅ **资源优化**
+- 避免创建多个音频实例
+- 自动清理无用的音频资源
+
+### ✅ **用户体验**
+- 页面跳转时音频播放不中断
+- 图标状态显示正确
+- 音频控制逻辑一致
+
+## 注意事项
+
+1. **页面生命周期**:音频实例与页面生命周期解耦,需要手动管理
+2. **内存管理**:确保在应用退出时正确清理音频资源
+3. **状态同步**:多个AudioControl组件需要监听相同的全局状态
+4. **错误处理**:增强错误处理机制,确保音频异常时的状态恢复
+
+## 兼容性
+
+- ✅ uni-app
+- ✅ 小程序环境
+- ✅ H5环境
+- ✅ APP环境
\ No newline at end of file
diff --git a/components/音频背景音乐交互说明.md b/components/音频背景音乐交互说明.md
new file mode 100644
index 0000000..c77ad71
--- /dev/null
+++ b/components/音频背景音乐交互说明.md
@@ -0,0 +1,144 @@
+# 音频与背景音乐交互功能说明
+
+## Bug修复记录
+
+### 问题描述
+当音频播放时点击背景音乐按钮,背景音乐暂停音频并开始播放。此时再点击关闭背景音乐,图标显示关闭状态但背景音乐仍在播放。
+
+### 问题原因
+1. 点击背景音乐按钮时会发送事件暂停音频
+2. 音频暂停时会调用restoreBackgroundMusic恢复背景音乐
+3. 然后MusicControl再执行自己的切换逻辑
+4. 导致背景音乐被恢复后又被操作,状态混乱
+
+### 解决方案
+1. **MusicControl组件优化**:
+ - 检测是否有音频在播放
+ - 如有音频,先暂停音频,延迟执行背景音乐切换
+ - 如无音频,直接切换背景音乐状态
+
+2. **AudioControl组件优化**:
+ - 在handleBackgroundMusicToggle中只暂停音频
+ - 不自动恢复背景音乐,让MusicControl自己控制
+
+### 修复后的交互流程
+```mermaid
+graph TD
+A[点击背景音乐按钮] --> B{是否有音频播放?}
+B -->|是| C[发送暂停音频事件]
+C --> D[AudioControl暂停音频\n不恢复背景音乐]
+D --> E[延迟100ms后切换背景音乐]
+B -->|否| F[直接切换背景音乐状态]
+```
+
+## 实现的功能
+
+### 🎵 **背景音乐控制音频**
+当点击背景音乐控制按钮时:
+- 如果有音频正在播放,会自动暂停音频
+- 然后正常切换背景音乐的播放/暂停状态
+
+### 🎧 **音频控制背景音乐**
+当点击音频控制按钮时:
+- 播放音频时自动暂停背景音乐
+- 暂停音频时自动恢复背景音乐
+- 音频播放结束时自动恢复背景音乐
+
+## 技术实现
+
+### 事件通信机制
+使用uni-app的全局事件机制实现组件间通信:
+
+```javascript
+// AudioControl组件发送事件
+uni.$emit('audioPlaying', true/false);
+
+// MusicControl组件发送事件
+uni.$emit('backgroundMusicToggle');
+
+// 组件监听事件
+uni.$on('eventName', this.handlerFunction);
+```
+
+### 交互流程
+
+#### 点击背景音乐按钮:
+```mermaid
+graph TD
+A[点击背景音乐按钮] --> B[发送backgroundMusicToggle事件]
+B --> C[AudioControl收到事件]
+C --> D{音频是否在播放?}
+D -->|是| E[暂停音频]
+D -->|否| F[继续背景音乐操作]
+E --> G[恢复背景音乐]
+F --> H[切换背景音乐状态]
+```
+
+#### 点击音频按钮:
+```mermaid
+graph TD
+A[点击音频按钮] --> B{当前音频状态?}
+B -->|未播放| C[暂停背景音乐]
+C --> D[播放音频]
+D --> E[发送audioPlaying:true事件]
+B -->|正在播放| F[暂停音频]
+F --> G[恢复背景音乐]
+G --> H[发送audioPlaying:false事件]
+```
+
+## 使用方法
+
+在页面中同时使用两个组件:
+
+```vue
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+## 优势特点
+
+### ✅ **智能交互**
+- 两个组件能够智能感知对方的状态
+- 避免同时播放音频和背景音乐造成的冲突
+- 提供良好的用户体验
+
+### ✅ **解耦设计**
+- 组件间通过事件通信,保持松耦合
+- 每个组件都能独立工作
+- 易于维护和扩展
+
+### ✅ **状态同步**
+- 实时同步音频和背景音乐的播放状态
+- 确保状态的一致性和准确性
+
+## 注意事项
+
+1. **事件监听清理**:组件销毁时会自动清理事件监听,避免内存泄漏
+2. **状态管理**:两个组件都维护各自的状态,通过事件保持同步
+3. **错误处理**:包含完善的错误处理机制,确保功能稳定运行
\ No newline at end of file
diff --git a/main.js b/main.js
index 96732c3..a38e368 100644
--- a/main.js
+++ b/main.js
@@ -4,6 +4,7 @@ import App from './App'
import store from './store'
import '@/static/js/request.js'
import '@/static/js/CommonFunction.js'
+import '@/utils/globalAudioManager.js'
import {myMixins} from '@/mixins/myMixins.js'
Vue.mixin(myMixins)
diff --git a/pages.json b/pages.json
index 420a58a..fcf6767 100644
--- a/pages.json
+++ b/pages.json
@@ -604,13 +604,6 @@
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
- },
- {
- "path": "chapter7/index",
- "style": {
- "navigationBarTitleText": "",
- "navigationStyle": "custom"
- }
}
]
}
diff --git a/pages/index/readingBody.vue b/pages/index/readingBody.vue
index b68e37b..46a71d2 100644
--- a/pages/index/readingBody.vue
+++ b/pages/index/readingBody.vue
@@ -60,7 +60,7 @@
-
+
@@ -110,6 +110,8 @@
app.initBackgroundMusic(); // 初始化背景音乐
uni.$bgMusic.play(); // 播放音乐
}
+ // 暂停所有其他音频(保留背景音乐)
+ this.pauseAllOtherAudio();
},
methods: {
sendRequest() {
@@ -188,6 +190,18 @@
uni.navigateTo({
url:'/subPackages/letter/detail?id='+item.id
})
+ },
+ // 暂停所有其他音频(AudioControl组件的音频)
+ pauseAllOtherAudio() {
+ try {
+ // 暂停全局音频(AudioControl组件的音频)
+ if (uni.$globalAudio && uni.$globalAudio.isAudioPlaying()) {
+ uni.$globalAudio.pauseCurrentAudio();
+ console.log('readingBody: 暂停其他音频,只保留背景音乐');
+ }
+ } catch (error) {
+ console.error('readingBody: 暂停音频失败:', error);
+ }
}
}
}
diff --git a/pig/chapter1/chapter1.vue b/pig/chapter1/chapter1.vue
index 9945e6d..6a34e97 100644
--- a/pig/chapter1/chapter1.vue
+++ b/pig/chapter1/chapter1.vue
@@ -104,10 +104,12 @@
+
+ @font-face {
+ font-family: "SourceHanSerif-Regular";
+ src: url(/static/fonts/SourceHanSerifSC-Regular.otf);
+ }
+
+ .main-swiper {
+ width: 100%;
+ height: 100vh;
+ }
+
+ .page-container {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ height: 100%;
+ position: relative;
+ overflow: hidden;
+ }
+
+ .loadedPages-three {
+ height: 100%;
+ position: relative;
+ background: #efefef;
+ display: flex;
+ align-items: center;
+ flex-direction: column;
+ justify-content: center;
+ }
+
+ .loadedPages-three-content {
+ height: 100%;
+
+ .loadedPages-three-title {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ width: 100%;
+ margin-top: 30rpx;
+
+ .txt {
+ font-size: 24rpx;
+ color: #333;
+ font-family: SourceHanSerif-Regular;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+
+ text {
+ display: block;
+ }
+ }
+
+ .txt:first-child {
+ margin-left: 30rpx;
+ }
+
+ .txt:last-child {
+ margin-right: 30rpx;
+ }
+ }
+
+ .loadedPages-three-center {
+ position: relative;
+
+ .desc {
+ display: flex;
+ flex-direction: column;
+ font-family: SourceHanSerif-Regular;
+ font-size: 90rpx;
+ color: #ec4899;
+
+ text {
+ display: block;
+ }
+ }
+
+ .en-desc {
+ display: flex;
+ flex-direction: column;
+ position: absolute;
+ top: 50%;
+ right: 0;
+ transform: translate(-25%, -50%);
+ font-size: 24rpx;
+ font-style: italic;
+ color: #4b5563;
+
+ text {
+ display: block;
+ }
+ }
+ }
+
+ .loadedPages-three-bottom {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ margin-bottom: 30rpx;
+
+ .bottom-img {
+ width: 400rpx;
+ height: 120rpx;
+ }
+
+ .bottom-tit {
+ font-size: 38rpx;
+ }
+
+ .bottom-txt {
+ font-size: 24rpx;
+ font-style: italic;
+ color: #4b5563;
+ }
+ }
+ }
+
+ .bg-image {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 1;
+ }
+
+ .content-layer {
+ position: relative;
+ z-index: 2;
+ width: 100%;
+ height: 100%;
+ display: flex;
+ align-items: center;
+ flex-direction: column;
+ }
+
+ .content-layer2 {
+ z-index: 2;
+ position: absolute;
+ bottom: 5%;
+ right: 5%;
+ }
+
+ .layer-img {
+ width: 650rpx;
+ height: 100%;
+ }
+
+ .arrow-down {
+ width: 100rpx;
+ height: 40rpx;
+ animation: bounce 1.5s infinite;
+ }
+
+ .layer-icon {
+ width: 100rpx;
+ height: 100rpx;
+ animation: bounce 1.5s infinite;
+ }
+
+ .overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: rgba(0, 0, 0, 0.3);
+ z-index: 10;
+ }
+
+ .fixed-nav {
+ width: 80rpx;
+ height: 80rpx;
+ background-color: rgb(0 0 0 / 0.7);
+ border-radius: 10rpx 0 0 10rpx;
+ position: fixed;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ margin: auto 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 9;
+ transition: transform 0.3s ease, opacity 0.3s ease;
+ }
+
+ .fixed-nav.hidden {
+ transform: translateX(100%);
+ opacity: 0;
+ pointer-events: none;
+ }
+
+ .nav-icon {
+ width: 35rpx;
+ height: 35rpx;
+ transition: transform 0.3s ease;
+ }
+
+ .nav-icon.rotated {
+ transform: rotate(180deg);
+ }
+
+ .nav-icon.bounce-back {
+ animation: bounceRotation 0.5s ease;
+ }
+
+ @keyframes bounceRotation {
+ 0% {
+ transform: rotate(180deg);
+ }
+
+ 50% {
+ transform: rotate(-20deg);
+ }
+
+ 75% {
+ transform: rotate(10deg);
+ }
+
+ 100% {
+ transform: rotate(0deg);
+ }
+ }
+
+ .nav-menu {
+ position: fixed;
+ top: 50%;
+ right: 0;
+ transform: translate(100%, -50%);
+ z-index: 11;
+ background-color: rgba(255, 255, 255, 0.95);
+ border-radius: 16rpx 0 0 16rpx;
+ box-shadow: -4px 0 15px rgba(0, 0, 0, 0.1);
+ transition: transform 0.3s ease;
+ }
+
+ .nav-menu.show {
+ transform: translate(0, -50%);
+ }
+
+ .nav-item {
+ padding: 20rpx;
+ text-align: center;
+
+ text {
+ color: #333;
+ opacity: 0.7;
+ font-size: 28rpx;
+ }
+ }
+
+ .item-active {
+ background-color: rgba(0, 0, 0, 0.1);
+ }
+
+ .nav-item .active {
+ color: #333;
+ opacity: 1;
+ }
+
+ .chapter-text {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ line-height: 1.3;
+ }
+
+ .chapter-title {
+ color: #333;
+ opacity: 0.7;
+ font-size: 24rpx;
+ }
+
+ .chapter-number {
+ color: #333;
+ opacity: 0.7;
+ font-size: 28rpx;
+ margin-top: 8rpx;
+ }
+
+ .item-active .chapter-title,
+ .item-active .chapter-number.active {
+ opacity: 1;
+ }
+
+ @keyframes bounce {
+
+ 0%,
+ 20%,
+ 50%,
+ 80%,
+ 100% {
+ transform: translateY(0);
+ }
+
+ 40% {
+ transform: translateY(-20rpx);
+ }
+
+ 60% {
+ transform: translateY(-10rpx);
+ }
+ }
+
+ .blur-to-clear {
+ animation: blurToClear 1.5s ease-out forwards;
+ }
+
+ @keyframes blurToClear {
+ 0% {
+ filter: blur(10px);
+ opacity: 0.3;
+ }
+
+ 100% {
+ filter: blur(0);
+ opacity: 1;
+ }
+ }
+
+ .hidden {
+ opacity: 0;
+ }
+
+ .bounce-in {
+ animation: bounceIn 1s ease forwards;
+ }
+
+ @keyframes bounceIn {
+ 0% {
+ opacity: 0;
+ transform: scale(0.3) translateY(100px);
+ }
+
+ 50% {
+ opacity: 1;
+ transform: scale(1.05) translateY(-10px);
+ }
+
+ 70% {
+ transform: scale(0.9) translateY(5px);
+ }
+
+ 100% {
+ opacity: 1;
+ transform: scale(1) translateY(0);
+ }
+ }
+
+ .fade-slide-up {
+ animation: fadeSlideUp 1s ease-out forwards;
+ }
+
+ @keyframes fadeSlideUp {
+ 0% {
+ opacity: 0;
+ transform: translateY(30px);
+ }
+
+ 100% {
+ opacity: 1;
+ transform: translateY(0);
+ }
+ }
+
+ .chapterCover-btn {
+ position: absolute;
+ left: 50%;
+ bottom: 10%;
+ transform: translate(-50%, -50%);
+ width: 300rpx;
+ height: 100rpx;
+ z-index: 2;
+ }
+
+ .qrcode-txt {
+ width: 30vw;
+ z-index: 2;
+ position: fixed;
+ left: 0;
+ right: 0;
+ margin: 100rpx auto 0;
+ }
+
+ .qrcode-txts {
+ width: 28vw;
+ z-index: 2;
+ position: fixed;
+ left: 0;
+ right: 0;
+ margin: 335rpx auto 0;
+ }
+
+ .message-board {
+ width: 100%;
+ }
+
+ .qrCode-image {
+ position: absolute;
+ left: 0;
+ right: 0;
+ bottom: 192rpx;
+ margin: 0 auto;
+ z-index: 2;
+ width: 30vw;
+ }
+
+ .image-popup-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: rgba(0, 0, 0, 0.8);
+ z-index: 9999;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+
+ .image-popup-container {
+ position: relative;
+ max-width: 90vw;
+ max-height: 90vh;
+ }
+
+ .popup-image {
+ width: 750rpx;
+ height: 654rpx;
+ max-width: 100%;
+ max-height: 100%;
+ }
+
+ .close-btn {
+ position: absolute;
+ top: -20rpx;
+ right: -20rpx;
+ width: 60rpx;
+ height: 60rpx;
+ background-color: rgba(255, 255, 255, 0.9);
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 40rpx;
+ color: #333;
+ cursor: pointer;
+ }
+
\ No newline at end of file
diff --git a/static/js/CommonFunction.js b/static/js/CommonFunction.js
index e5dd4b1..723a463 100644
--- a/static/js/CommonFunction.js
+++ b/static/js/CommonFunction.js
@@ -167,9 +167,101 @@ Vue.prototype._requestLocation = function(callback) {
// 路由页面跳转
Vue.prototype.gotoPath = path => {
+ console.log(path,'pathpath');
+
+ // 参数验证
+ if (!path || typeof path !== 'string') {
+ console.error('gotoPath: 路径参数无效', path);
+ return;
+ }
+
+ // 清理路径,移除多余的空格和特殊字符
+ path = path.trim();
+
+ // 检查是否为有效路径格式
+ if (!path.startsWith('/')) {
+ console.error('gotoPath: 路径必须以/开头', path);
+ return;
+ }
+
+ // 获取当前页面栈
+ const pages = getCurrentPages();
+ const currentPage = pages[pages.length - 1];
+ const currentPath = currentPage ? currentPage.route : '';
+
+ // 避免重复跳转到同一页面
+ if (currentPath && ('/' + currentPath) === path) {
+ console.warn('gotoPath: 避免重复跳转到当前页面', path);
+ return;
+ }
+
+ // 检查页面栈深度,避免栈溢出
+ if (pages.length >= 10) {
+ console.warn('gotoPath: 页面栈过深,使用redirectTo替代', path);
+ uni.redirectTo({
+ url: path,
+ fail: (err) => {
+ console.error('redirectTo失败:', err, 'path:', path);
+ // 最后尝试reLaunch
+ uni.reLaunch({
+ url: path,
+ fail: (err2) => {
+ console.error('reLaunch也失败:', err2, 'path:', path);
+ }
+ });
+ }
+ });
+ return;
+ }
+
+ // 防抖处理,避免快速重复点击
+ if (Vue.prototype._lastNavigateTime && Date.now() - Vue.prototype._lastNavigateTime < 500) {
+ console.warn('gotoPath: 防抖拦截,请勿频繁点击');
+ return;
+ }
+ Vue.prototype._lastNavigateTime = Date.now();
+
+ // 尝试正常跳转
uni.navigateTo({
- url: path
- })
+ url: path,
+ success: (res) => {
+ console.log('跳转成功:', path);
+ },
+ fail: (err) => {
+ console.error('navigateTo失败:', err, 'path:', path);
+
+ // 如果是tabBar页面,使用switchTab
+ if (err.errMsg && err.errMsg.includes('tabbar')) {
+ console.log('检测到tabBar页面,使用switchTab');
+ uni.switchTab({
+ url: path,
+ fail: (err2) => {
+ console.error('switchTab也失败:', err2, 'path:', path);
+ }
+ });
+ } else if (err.errMsg && err.errMsg.includes('limit exceed')) {
+ // 页面栈超限,使用redirectTo
+ console.log('页面栈超限,使用redirectTo');
+ uni.redirectTo({
+ url: path,
+ fail: (err3) => {
+ console.error('redirectTo也失败:', err3, 'path:', path);
+ }
+ });
+ } else {
+ // 其他错误,尝试延迟重试
+ console.log('延迟重试跳转');
+ setTimeout(() => {
+ uni.navigateTo({
+ url: path,
+ fail: (err4) => {
+ console.error('延迟重试也失败:', err4, 'path:', path);
+ }
+ });
+ }, 300);
+ }
+ }
+ });
}
// 返回上一页
diff --git a/taozi/chapter1/chapter1.vue b/taozi/chapter1/chapter1.vue
index ec711c9..e86bfe4 100644
--- a/taozi/chapter1/chapter1.vue
+++ b/taozi/chapter1/chapter1.vue
@@ -1,6 +1,7 @@
+
@@ -87,10 +88,12 @@
@@ -94,7 +78,15 @@
width: 100vw;
height: 100vh;
}
-
+ .imgJump{
+ position: absolute;
+ bottom:100rpx;
+ left:250rpx;
+ width: 273rpx;
+ height: 85rpx;
+ opacity: 0.8;
+ z-index: 999999;
+ }
.swiper-item {
width: 100vw;
height: 100vh;
@@ -120,7 +112,7 @@
margin: 0 auto;
bottom: 70rpx;
}
-
+
.img3-btn {
width: 558rpx;
line-height: 72rpx;
@@ -135,17 +127,17 @@
margin: 0 auto;
bottom: 180rpx;
}
-
+
.flex-column {
position: absolute;
bottom: 280rpx;
width: 100%;
align-items: center;
-
+
.img5-text {
width: 100%;
}
-
+
.img5-btn {
width: 230rpx;
margin-top: 99rpx;
diff --git a/xqk/chapter6/index.vue b/xqk/chapter6/index.vue
index a9ea516..91e1b20 100644
--- a/xqk/chapter6/index.vue
+++ b/xqk/chapter6/index.vue
@@ -3,109 +3,65 @@
-
-
-
-
-
- {{item}}
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -123,15 +79,32 @@
background-color: #000;
background-repeat: no-repeat;
position: relative;
-
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ .item-box{
+ .box-two{
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ }
+ position: absolute;
+ top:289rpx;
+ left:99rpx;
+ .img2-text{
+ width: 257rpx;
+ }
+ }
.btn-img {
position: absolute;
width: 149.8rpx;
bottom: 290rpx;
left: 84rpx;
}
-
- .img7-1, .img7-2 {
+
+ .img7-1,
+ .img7-2 {
width: 437.67rpx;
position: absolute;
left: 0;
@@ -139,7 +112,7 @@
margin: 0 auto;
top: 365rpx;
}
-
+
.bgm-box {
width: 437.67rpx;
position: absolute;
@@ -148,7 +121,7 @@
bottom: 650rpx;
margin: 0 auto;
flex-wrap: wrap;
-
+
view {
width: 207.89rpx;
line-height: 42.77rpx;
@@ -158,16 +131,17 @@
font-size: 20rpx;
border: 1rpx solid #fff;
}
+
view:nth-child(n+3) {
margin-top: 17rpx;
}
-
+
.bgm-active {
border-color: #00C48C;
color: #00C48C;
}
}
-
+
.img7-btn {
width: 439.66rpx;
position: absolute;
@@ -182,14 +156,14 @@
width: 100vw;
height: 100vh;
}
-
+
.popup-content {
width: 85vw;
background-color: #fff;
border-radius: 16rpx;
padding: 40rpx 30rpx;
box-sizing: border-box;
-
+
.input-area {
width: 100%;
min-height: 180rpx;
@@ -201,14 +175,14 @@
box-sizing: border-box;
margin-bottom: 15rpx;
}
-
+
.word-count {
text-align: right;
font-size: 24rpx;
color: #999;
margin-bottom: 35rpx;
}
-
+
.confirm-btn {
width: 100%;
}
diff --git a/xqk/chapter7/index.vue b/xqk/chapter7/index.vue
deleted file mode 100644
index 5c804af..0000000
--- a/xqk/chapter7/index.vue
+++ /dev/null
@@ -1,143 +0,0 @@
-
-
-
-
-
-
-
-
- {{info.text1}}
-
- {{info.text2}}
-
- {{info.imgTitle}}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/xqk/chapter8/index.vue b/xqk/chapter8/index.vue
deleted file mode 100644
index 0b339f9..0000000
--- a/xqk/chapter8/index.vue
+++ /dev/null
@@ -1,75 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/xqk/components/NavMenu.vue b/xqk/components/NavMenu.vue
index ac3e469..c7b787d 100644
--- a/xqk/components/NavMenu.vue
+++ b/xqk/components/NavMenu.vue
@@ -60,7 +60,7 @@
path: "/xqk/chapter3/index"
},
{
- text: '04 风味人间',
+ text: '04 蟹在人间',
targetIndex: 4,
path: "/xqk/chapter4/index"
},
@@ -72,7 +72,7 @@
{
text: '有感商品',
targetIndex: 6,
- path: "/subPackages/techan/detail?id=39"
+ path: "/subPackages/techan/detail?id=40"
},
{
text: '购物车',
@@ -108,7 +108,7 @@
this.$emit('menu-hide');
},
onJumpToPage(item) {
- console.log(this.navIndex)
+ console.log(this.navIndex,item.targetIndex,item.path)
if(item.path && item.targetIndex != this.navIndex) this.gotoPath(item.path)
this.onCloseMenu();
},
diff --git a/xqk/home/home.vue b/xqk/home/home.vue
index 3dfbd33..a4e39d5 100644
--- a/xqk/home/home.vue
+++ b/xqk/home/home.vue
@@ -1,33 +1,33 @@
-
+
-
+
-
+
+
+
-
+
+
-
+