实况照片功能完整实现文档

实况照片功能完整实现文档

1. 功能概述

1.1 项目背景

这个是温柔猫进行的原创的二次修改
实况照片功能是基于AnZhiYu主题基础再次开发的一个增强功能,旨在支持苹果设备拍摄的Live Photo在网页端的展示和交互。该功能经历了从基础版本到完整优化版本的迭代开发。

1.2 功能演进历程

版本1.0 - 基础实况照片功能

  • 核心功能: 支持实况照片的基本播放
  • 交互方式: 鼠标悬停播放
  • 显示效果: 进度条显示播放进度
  • 智能封面: 自动提取视频首帧作为封面

版本2.0 - 长按播放优化

  • 双模式支持: 悬停模式(hover) + 长按模式(press)
  • 可配置进度条: 支持显示/隐藏进度条
  • 自定义延迟: 可配置长按触发延迟时间
  • 移动端适配: 完整的触摸事件支持
  • UI/UX优化: 长按提示、视觉反馈等

版本3.0 - 加载优化

  • 多重初始化: 解决首次加载适配问题
  • 动态内容支持: MutationObserver监听DOM变化
  • 性能优化: 防重复初始化、错误处理
  • 稳定性提升: 多种加载时机适配

1.3 功能模块详解

1.3.1 核心播放引擎

1
2
3
4
5
6
class LivePhoto {
constructor() {
this.containers = []; // 存储所有实况照片容器
this.init(); // 初始化功能
}
}

作用: 管理所有实况照片实例,提供统一的初始化和控制接口。

1.3.2 智能封面系统 暂时还没有实现!!!,后续会根据需求进行实现。

1
2
3
4
async handleSmartCover(container, video, stillImage) {
// 自动提取视频首帧作为封面
// 处理视频加载失败的降级方案
}

作用: 自动提取视频首帧,确保封面图片的一致性和美观度。

1.3.3 交互控制系统

1
2
3
4
5
6
7
bindEvents(data) {
if (data.playMode === 'hover') {
// 悬停播放逻辑
} else if (data.playMode === 'press') {
// 长按播放逻辑
}
}

作用: 根据配置提供不同的交互方式,适应不同使用场景。

1.3.4 进度显示系统

1
2
3
4
startProgress(data) {
if (!data.showProgress) return;
// 创建和控制进度条显示
}

作用: 可配置的进度条显示,提供视觉反馈。

2. 分步安装指南

2.1 环境准备

2.1.1 基础环境要求

  • Node.js: 版本 >= 14.0.0
  • Hexo: 版本 >= 5.0.0
  • AnZhiYu主题: 最新版本
  • 浏览器: 支持ES6+的现代浏览器

2.1.2 检查环境

1
2
3
4
5
6
7
8
# 检查Node.js版本
node --version

# 检查Hexo版本
hexo version

# 检查主题版本
cat themes/anzhiyu/package.json | grep version

2.2 依赖项安装

2.2.1 核心依赖

实况照片功能基于原生JavaScript开发,无需额外安装npm包。

2.2.2 主题依赖确认

确保AnZhiYu主题已正确安装:

1
2
3
4
5
# 进入博客根目录
cd your-blog-directory

# 检查主题文件
ls themes/anzhiyu/

2.3 配置文件设置

2.3.1 创建相册配置文件

source/_data/album.yml 中添加实况照片配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- class_name: "实况照片展示"
path_name: "/livePhotos"
type: 1
description: "支持苹果Live Photo的动态展示"
album_list:
- content: "春日樱花盛开"
live_photo:
enable: true
still_image: "/images/live-photos/sakura-still.jpg"
video: "/images/live-photos/sakura-video.mp4"
duration: 3
play_mode: "press" # hover 或 press
show_progress: false # true 或 false
press_delay: 300 # 毫秒
- content: "夕阳西下美景"
live_photo:
enable: true
still_image: "/images/live-photos/sunset-still.jpg"
video: "/images/live-photos/sunset-video.mp4"
duration: 2.5
play_mode: "hover"
show_progress: true
press_delay: 500

2.3.2 创建页面文件

source/livePhotos/index.md 中创建页面:

1
2
3
4
5
6
---
title: 实况照片
date: 2024-01-15
type: "album"
layout: "album"
---

3. 完整部署流程

3.1 文件部署步骤

步骤1: 复制JavaScript文件

1
2
# 将live_photo.js复制到主题js目录
cp live_photo.js themes/anzhiyu/source/js/

步骤2: 复制CSS样式文件

1
2
# 将live_photo.css复制到主题css目录
cp live_photo.css themes/anzhiyu/source/css/_extra/album/

步骤3: 更新模板文件

编辑 themes/anzhiyu/layout/includes/page/album_detail.pug,添加实况照片支持:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if item.live_photo && item.live_photo.enable
.album-container-img
- let posterSrc = item.live_photo.poster || item.live_photo.still_image
- let playMode = item.live_photo.play_mode || 'hover'
- let showProgress = item.live_photo.show_progress !== false
- let pressDelay = item.live_photo.press_delay || 300
.live-photo-container(data-duration=item.live_photo.duration data-play-mode=playMode data-show-progress=showProgress data-press-delay=pressDelay)
.live-photo-wrapper
img.live-photo-still(src=item.live_photo.still_image alt=item.content)
video.live-photo-video(preload="none" muted loop playsinline poster=posterSrc)
source(src=item.live_photo.video type="video/mp4")
.live-photo-controls
.live-photo-play-btn
i.anzhiyufont.anzhiyu-icon-play
.live-photo-indicator LIVE
.live-photo-cover-status(style="display: none;")
span.cover-status-text 正在提取封面...

步骤4: 更新JavaScript引入

编辑 themes/anzhiyu/layout/includes/additional-js.pug,添加:

1
2
//- 实况照片功能
script(async data-pjax src="/js/live_photo.js")

3.2 资源文件准备

3.2.1 创建媒体文件目录

1
2
# 创建实况照片资源目录
mkdir -p source/images/live-photos

3.2.2 准备媒体文件

  • 静态图片: JPG/PNG格式,建议尺寸1080x1080或16:9
  • 视频文件: MP4格式,时长2-5秒,建议码率适中
  • 文件命名: 使用有意义的名称,如 sakura-still.jpgsakura-video.mp4
  • 建议从icloud进行下载 https://www.icloud.com.cn/

3.3 可能出现的问题及解决方案

问题1: 视频无法播放

现象: 实况照片显示静态图片,但无法播放视频
原因: 视频文件路径错误或格式不支持
解决方案:

1
2
3
4
5
# 检查文件是否存在
ls source/images/live-photos/

# 检查视频格式
file source/images/live-photos/your-video.mp4

问题2: 首次加载不显示

现象: 需要刷新页面才能正常显示
原因: JavaScript初始化时机问题
解决方案: 已在v3.0版本中修复,确保使用最新版本的live_photo.js

问题3: 移动端触摸无效

现象: 在移动设备上无法触发播放
原因: 触摸事件绑定问题
解决方案: 检查CSS中的touch-action属性设置

问题4: 进度条不显示

现象: 配置了show_progress: true但进度条不显示
原因: CSS样式冲突或配置读取错误
解决方案:

1
2
// 在浏览器控制台检查配置
console.log(document.querySelector('.live-photo-container').dataset);

4. 代码部署说明

4.1 代码结构解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
themes/anzhiyu/
├── source/
│ ├── js/
│ │ └── live_photo.js # 核心JavaScript文件
│ └── css/
│ └── _extra/
│ └── album/
│ └── live_photo.css # 样式文件
├── layout/
│ └── includes/
│ ├── page/
│ │ └── album_detail.pug # 页面模板
│ └── additional-js.pug # JavaScript引入
source/
├── _data/
│ └── album.yml # 配置文件
├── images/
│ └── live-photos/ # 媒体资源目录
└── livePhotos/
└── index.md # 页面文件

4.2 关键配置参数说明

4.2.1 基础配置参数

1
2
3
4
5
live_photo:
enable: true # 是否启用实况照片
still_image: "path/to/image" # 静态图片路径
video: "path/to/video" # 视频文件路径
duration: 3 # 播放时长(秒)

4.2.2 交互配置参数

1
2
3
play_mode: "press"              # 播放模式: hover/press
show_progress: false # 是否显示进度条
press_delay: 300 # 长按延迟(毫秒)

4.2.3 高级配置参数

1
2
3
poster: "path/to/poster"        # 自定义封面(可选)
preload: "none" # 视频预加载策略
loop: true # 是否循环播放

4.3 JavaScript API说明

4.3.1 全局对象

1
2
3
4
5
6
7
8
// 全局实况照片对象
window.livePhoto

// 手动刷新所有实况照片
window.livePhoto.refresh();

// 销毁所有实况照片
window.livePhoto.destroy();

4.3.2 事件监听

1
2
3
4
5
6
7
8
9
// PJAX页面切换事件
document.addEventListener('pjax:complete', () => {
window.livePhoto.refresh();
});

// 页面加载完成事件
window.addEventListener('load', () => {
window.livePhoto.refresh();
});

4.4 CSS类名说明

4.4.1 容器类名

1
2
3
4
5
.live-photo-container          /* 主容器 */
.live-photo-wrapper /* 内容包装器 */
.live-photo-still /* 静态图片 */
.live-photo-video /* 视频元素 */
.live-photo-controls /* 控制元素容器 */

4.4.2 控制元素类名

1
2
3
4
.live-photo-play-btn          /* 播放按钮 */
.live-photo-indicator /* LIVE标识 */
.live-photo-progress /* 进度条 */
.live-photo-cover-status /* 封面状态提示 */

4.4.3 状态类名

1
2
3
.playing                      /* 播放状态 */
.loading /* 加载状态 */
.error /* 错误状态 */

4.5 测试和验证方法

4.5.1 功能测试清单

  • 静态图片正常显示
  • 悬停/长按触发播放
  • 视频播放流畅
  • 进度条显示正确
  • 移动端触摸正常
  • 页面切换后功能正常
  • 多个实况照片同时工作

4.5.2 性能测试

1
2
3
4
5
6
7
// 检查内存使用
console.log(performance.memory);

// 检查加载时间
console.time('livePhotoInit');
window.livePhoto.refresh();
console.timeEnd('livePhotoInit');

4.5.3 兼容性测试

  • 桌面端: Chrome 80+, Firefox 75+, Safari 13+, Edge 80+
  • 移动端: iOS Safari 13+, Chrome Mobile 80+, Samsung Internet 12+

4.5.4 调试方法

1
2
3
4
5
6
7
8
9
10
// 开启调试模式
window.livePhoto.debug = true;

// 查看容器信息
console.log(window.livePhoto.containers);

// 检查配置读取
document.querySelectorAll('.live-photo-container').forEach(container => {
console.log('配置:', container.dataset);
});

5. 高级配置和自定义

5.1 自定义样式

5.1.1 修改进度条样式

1
2
3
4
5
.live-photo-progress {
background: linear-gradient(90deg, #ff6b6b, #4ecdc4);
height: 4px;
border-radius: 2px;
}

5.1.2 自定义长按提示 现在没有提示了,后续会根据需求进行添加。

1
2
3
4
.live-photo-container[data-play-mode="press"]::after {
content: "长按播放";
/* 自定义样式 */
}

5.2 扩展功能开发

5.2.1 添加音频支持

1
2
3
4
5
6
// 在setupLivePhoto方法中添加
const audio = container.querySelector('.live-photo-audio');
if (audio) {
data.audio = audio;
// 同步音频播放
}

5.2.2 添加全屏播放

1
2
3
4
5
6
// 添加全屏播放功能
fullscreenPlay(data) {
if (data.video.requestFullscreen) {
data.video.requestFullscreen();
}
}

6. 维护和更新

6.1 版本更新流程

  1. 备份现有文件
  2. 下载新版本文件
  3. 对比配置差异
  4. 更新文件并测试
  5. 部署到生产环境

6.2 常见维护任务

  • 定期检查媒体文件完整性
  • 监控页面加载性能
  • 更新浏览器兼容性
  • 优化媒体文件大小

6.3 常见问题修复

6.3.1 LivePhoto重复声明错误修复

问题描述
在浏览器控制台出现 Uncaught SyntaxError: Identifier 'LivePhoto' has already been declared 错误,这是由于 live_photo.js 文件被多次加载导致的类重复声明。

错误原因

  • PJAX页面切换时重复加载脚本
  • 浏览器缓存问题
  • 多个页面同时引用相同脚本

修复步骤

  1. 添加条件检查
    themes/anzhiyu/source/js/live_photo.js 文件中,为 LivePhoto 类声明添加条件检查:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 防止重复声明LivePhoto类
if (typeof window.LivePhoto === 'undefined') {
class LivePhoto {
constructor() {
this.containers = new Map();
this.debug = false;
this.init();
}

// ... 其他方法保持不变
}

// 将LivePhoto类添加到全局作用域
window.LivePhoto = LivePhoto;

// 创建全局实例
if (!window.livePhoto) {
window.livePhoto = new LivePhoto();
}

// 模块导出(如果需要)
if (typeof module !== 'undefined' && module.exports) {
module.exports = LivePhoto;
}
}
  1. 增强事件监听器安全性
    为事件监听器添加安全检查:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// PJAX兼容性
if (typeof window.addEventListener !== 'undefined') {
window.addEventListener('pjax:complete', () => {
if (window.livePhoto && typeof window.livePhoto.refresh === 'function') {
window.livePhoto.refresh();
}
});

window.addEventListener('load', () => {
if (window.livePhoto && typeof window.livePhoto.refresh === 'function') {
window.livePhoto.refresh();
}
});
}
  1. 清理缓存并重新生成
    1
    2
    npx hexo clean
    npx hexo generate

验证修复

  • 打开浏览器开发者工具
  • 刷新页面,检查控制台是否还有错误
  • 测试实况照片功能是否正常工作
  • 测试PJAX页面切换后功能是否正常

预防措施

  • 定期检查脚本重复加载问题
  • 使用条件检查防止全局变量重复声明
  • 在开发时启用调试模式监控脚本加载

6.4 故障排除工具

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 实况照片诊断工具
function diagnoseLivePhoto() {
const containers = document.querySelectorAll('.live-photo-container');
containers.forEach((container, index) => {
console.log(`容器 ${index}:`, {
initialized: container.dataset.livePhotoInitialized,
config: container.dataset,
video: container.querySelector('.live-photo-video'),
image: container.querySelector('.live-photo-still')
});
});
}

// 检查LivePhoto类是否正确加载
function checkLivePhotoStatus() {
console.log('LivePhoto状态检查:', {
classExists: typeof window.LivePhoto !== 'undefined',
instanceExists: typeof window.livePhoto !== 'undefined',
instanceType: typeof window.livePhoto,
methods: window.livePhoto ? Object.getOwnPropertyNames(Object.getPrototypeOf(window.livePhoto)) : 'N/A'
});
}

7. 总结

实况照片功能为AnZhiYu主题再次基础上提供了丰富的媒体展示能力,通过合理的配置和部署,可以为用户带来优秀的视觉体验。本文档涵盖了从基础安装到高级自定义的完整流程,确保开发者能够顺利部署和维护该功能。
本文档由野似o温柔猫+AI进行实现

如有问题,请参考故障排除章节或查看项目的GitHub仓库获取最新信息。
https://github.com/wenroumao/blog-wenroumao