hexo博客添加live动图
演示
支持声音功能,默认静音,可以调整长宽高 鼠标移动到live图上方自动循环播放
LIVE
LIVE
LIVE
LIVE
安装
在主题js和css文件夹添加livephoto.css、livephoto.js、csh.js
livephoto.css样式文件
/* 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); }
|
livephoto.js文件
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加载完成初始化csh.js
/** * 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(); });
|
配置
在 Hexo 的主题配置文件 _config.yml 中添加以下选项:
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 %}
|