惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

GbyAI
GbyAI
Y
Y Combinator Blog
Martin Fowler
Martin Fowler
D
Docker
N
Netflix TechBlog - Medium
酷 壳 – CoolShell
酷 壳 – CoolShell
WordPress大学
WordPress大学
L
LangChain Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园 - 三生石上(FineUI控件)
博客园_首页
量子位
罗磊的独立博客
Blog — PlanetScale
Blog — PlanetScale
云风的 BLOG
云风的 BLOG
Microsoft Azure Blog
Microsoft Azure Blog
宝玉的分享
宝玉的分享
Apple Machine Learning Research
Apple Machine Learning Research
D
DataBreaches.Net
I
InfoQ
Engineering at Meta
Engineering at Meta
The Cloudflare Blog
H
Help Net Security
V
V2EX

宇外御风

99元/年阿里云服务器搭建大华摄像头智能云回放(Frigate+ZLMediaKit极简方案) 用CloudflareWorker+D1数据库搭建MoonTVPlus 解决Hexo博客发布文章后更新不及时 蜜蜂记账一个开源免费安全的记账软件 更换vercel部署的Waline存储服务到TiDB 解决使能IPv6防火墙控制转发报文无法关闭 推荐三个应用tx box、lx音乐、阅读 24岁不上不下 试验检测师学习笔记 每日60秒新闻简报 让AI理解标签语法美化文章 宝塔自动部署拉取GitHub仓库的hexo博客 添加安知鱼主题页面卡片并美化 魅族20Pro系统更新支持朋友圈动图 搜索引擎如何发现你的博客 打造无缝影音体验:NAS自动化媒体库 + IPv6远程访问 + VidHub完美字幕支持 年轻人的第一台代步车福特嘉年华 蟹bro记又名01测量大帝 驾校科目一 铁路路基监测报告
hexo博客添加live动图
宇外御风 · 2025-09-02 · via 宇外御风
/* Live Photo 容器样式 */
.live-photo-container {
position: relative;
display: inline-block;
cursor: pointer;
overflow: hidden;
line-height: 0; /* 消除图片下方的间隙 */
border-radius: 8px; /* 容器圆角 */
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); /* 可选:轻微阴影提升质感 */
}

/* 图片和视频层叠 */
.live-photo-static,
.live-photo-video {
width: 100%;
height: auto;
transition: opacity 0.3s ease;
border-radius: 8px; /* 统一图片和视频的圆角值 */
}

/* 视频默认隐藏 */
.live-photo-video {
position: absolute;
top: 0;
left: 0;
opacity: 0;
object-fit: cover; /* 确保视频覆盖整个容器 */
}

/* 鼠标悬停时隐藏静态图,显示视频 */
.live-photo-container:hover .live-photo-static {
opacity: 0;
}

.live-photo-container:hover .live-photo-video {
opacity: 1;
}

/* Live 标志 */
.live-badge {
position: absolute;
top: 10px;
right: 10px;
z-index: 3;
background-color: rgba(0, 0, 0, 0.6);
color: #fff;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
pointer-events: none; /* 确保鼠标事件能穿透标志 */
opacity: 0.8;
display: flex;
align-items: center;
}

/* 红色闪烁点 */
.live-badge::before {
content: '';
display: inline-block;
width: 8px;
height: 8px;
background-color: #ff0000;
border-radius: 50%;
margin-right: 6px;
animation: blink 1.5s infinite;
}

@keyframes blink {
0% { opacity: 1; }
50% { opacity: 0.3; }
100% { opacity: 1; }
}

/* 静音按钮样式 - 位置调整 */
.live-photo-mute-btn {
position: absolute;
bottom: 25px; /* 从10px调整为15px,向上移动5px */
right: 10px;
z-index: 3;
background-color: rgba(0, 0, 0, 0.6);
color: #fff;
border: none;
border-radius: 50%;
width: 28px;
height: 28px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
font-size: 14px;
opacity: 0.8;
transition: opacity 0.2s ease;
}

.live-photo-mute-btn:hover {
opacity: 1;
background-color: rgba(0, 0, 0, 0.8);
}

document.addEventListener('DOMContentLoaded', function() {
const livePhotos = document.querySelectorAll('.live-photo-container');

livePhotos.forEach(container => {
const video = container.querySelector('.live-photo-video');
const muteBtn = container.querySelector('.live-photo-mute-btn');

// 初始化视频设置
video.loop = true;
video.muted = true;
video.playsInline = true;

// 更新静音按钮状态
const updateMuteButton = () => {
muteBtn.textContent = video.muted ? '🔇' : '🔊';
};
updateMuteButton();

// 静音按钮事件
muteBtn.addEventListener('click', (e) => {
e.stopPropagation();
video.muted = !video.muted;
updateMuteButton();
});

// 鼠标悬停事件
container.addEventListener('mouseenter', () => {
video.currentTime = 0;
video.play().catch(e => console.error("播放失败:", e));
});

container.addEventListener('mouseleave', () => {
video.pause();
video.currentTime = 0;
});

// 触摸设备支持
container.addEventListener('touchstart', (e) => {
e.preventDefault();
if (video.paused) {
video.play();
} else {
video.pause();
}
}, { passive: false });
});
});

/**
* PJAX加载完成后自动重新初始化(改进版)
* 解决初始化时机、事件绑定和组件状态问题
*/

// 初始化函数示例(实际使用时替换为您的初始化逻辑)
function initializeComponents() {
console.log("执行初始化...");
// 这里放置您的初始化代码,例如:
// - 绑定事件处理程序
// - 初始化UI组件
// - 设置状态变量
// - 加载动态内容

// 示例:初始化Live Photo组件
initLivePhotos();
}

// 初始化Live Photo组件(示例)
function initLivePhotos() {
const livePhotos = document.querySelectorAll('.live-photo-container');

livePhotos.forEach(container => {
// 确保组件只初始化一次
if (container.dataset.initialized) return;
container.dataset.initialized = "true";

const video = container.querySelector('.live-photo-video');
const muteBtn = container.querySelector('.live-photo-mute-btn');

// 确保视频循环播放且默认静音
video.loop = true;
video.muted = true;
video.playsInline = true;

// 静音按钮状态
let isMuted = true;

// 更新静音按钮图标
function updateMuteButton() {
muteBtn.innerHTML = isMuted ? '🔇' : '🔊';
}
updateMuteButton();

// 静音按钮点击事件
muteBtn.addEventListener('click', function(e) {
e.stopPropagation();
isMuted = !isMuted;
video.muted = isMuted;
updateMuteButton();
});

// 鼠标悬停播放视频
container.addEventListener('mouseenter', function() {
video.currentTime = 0;
video.play().catch(e => console.error("播放失败:", e));
});

// 鼠标离开暂停视频
container.addEventListener('mouseleave', function() {
video.pause();
video.currentTime = 0;
});
});
}

// 清理函数(在PJAX加载前执行)
function cleanupComponents() {
console.log("执行清理...");
// 这里放置清理代码,例如:
// - 移除事件监听器
// - 重置组件状态
// - 清理全局变量

// 示例:清理Live Photo组件的事件监听器
const livePhotos = document.querySelectorAll('.live-photo-container');
livePhotos.forEach(container => {
// 移除所有自定义事件监听器
const newContainer = container.cloneNode(true);
container.parentNode.replaceChild(newContainer, container);

// 重置初始化标记
delete container.dataset.initialized;
});
}

// 监听pjax:send事件(PJAX开始加载时)
document.addEventListener('pjax:send', function() {
console.log("PJAX开始加载,执行清理");
cleanupComponents();
});

// 监听pjax:success事件
document.addEventListener('pjax:success', function(event) {
console.log("PJAX加载完成,等待DOM更新");

// 使用MutationObserver确保DOM完全更新
const observer = new MutationObserver(function(mutations) {
observer.disconnect();
console.log("DOM更新完成,开始重新初始化");
initializeComponents();
});

// 观察整个文档的变化
observer.observe(document, {
childList: true,
subtree: true
});
});

// 页面首次加载时执行初始化
document.addEventListener('DOMContentLoaded', function() {
console.log("页面首次加载,执行初始化");
initializeComponents();
});

// 监听pjax:error事件
document.addEventListener('pjax:error', function(event) {
console.error("PJAX加载失败", event);
// 错误处理后可尝试重新初始化
initializeComponents();
});

inject:
head:
- <link rel="stylesheet" href="/css/livephoto.css">
bottom:
- <script src="/js/livephoto.js"></script>
- <script src="/js/csh.js"></script>
<!-- 在Hexo文章中使用时,用raw标签包裹 -->
{% raw %}
<div class="live-photo-container" style="width: 100%; max-width: 800px; height: auto;">
<!-- 静态图片 -->
<img src="https://cftcr2.20010501.xyz/PicHoro/1757173197761.webp"
class="live-photo-static"
alt="Live Photo"
data-photo-src="https://cftcr2.20010501.xyz/PicHoro/1757173197761.webp">

<!-- 动态视频 -->
<video class="live-photo-video"
preload="metadata"
muted
data-video-src="https://cftcr2.20010501.xyz/PicHoro/1757173192196.mp4">
<source src="https://cftcr2.20010501.xyz/PicHoro/1757173192196.mp4" type="video/mp4">
</video>

<!-- Live 标志 -->
<div class="live-badge">LIVE</div>

<!-- 静音切换按钮 -->
<button class="live-photo-mute-btn" aria-label="切换静音"></button>
</div>
{% endraw %}