Scrapy-入门篇
自定义文章内外链接样式的另一种方法(使用 markdown-it 插件)
rc.includes('data:image/gif'); if (this.videoFailed) { if (isImgInvalid) { // 情况 A:全错(视频坏了 + 图片也坏了) this.container.classList.add('is-total-error'); this.container.classList.remove('is-video-error'); // 必须移除,防止干扰 CSS } else { // 情况 B:仅视频错(视频坏了 + 图片是好的) this.container.classList.add('is-video-error'); this.container.classList.remove('is-total-error'); } } else { // 如果视频没坏,确保这两个错误类都不存在 this.container.classList.remove('is-total-error', 'is-video-error'); } } // 处理悬停开始 handleHoverStart() { // 清除之前的超时 if (this.hoverTimeout) clearTimeout(this.hoverTimeout); // 设置延迟播放 this.hoverTimeout = setTimeout(() => { this.play(); }, this.config.hover_delay || 300); } // 处理悬停结束 handleHoverEnd() { // 清除悬停超时 if (this.hoverTimeout) { clearTimeout(this.hoverTimeout); this.hoverTimeout = null; } // 如果视频是循环播放的(loop),鼠标移开必须立刻停止,否则声音和画面会在后台无限消耗 if (this.video.loop) { // 鼠标离开时,我们不停止视频,而是“静音”它 // 这样画面会继续循环播放,但声音会消失,解决了你担心的扰民问题 this.video.muted = true; if (this.soundToggle) { this.soundToggle.classList.remove("is-unmuted"); } } } // 显示加载指示器 showLoading() { let loadingEl = this.container.querySelector(".live-loading"); if (!loadingEl && this.config.loading_animation) { loadingEl = document.createElement("div"); loadingEl.className = "live-loading"; this.container.appendChild(loadingEl); } if (loadingEl) { loadingEl.style.display = "block"; } } // 隐藏加载指示器 hideLoading() { const loadingEl = this.container.querySelector(".live-loading"); if (loadingEl) { loadingEl.style.display = "none"; } } // 播放视频 play() { if (this.isPlaying) return; this.isPlaying = true; const playPromise = this.video.play(); if (playPromise !== undefined) { playPromise.catch(error => { // 处理由于浏览器策略导致的播放失败(如需要手动点击) console.warn("Live-Photo Play Interrupted:", error); this.stop(); }); } } // 停止播放 stop() { if (this.badgeTimer) clearTimeout(this.badgeTimer); this.container.classList.remove('is-loading'); this.container.classList.remove('is-playing'); this.video.classList.remove("playing"); this.staticImage.style.opacity = 1; this.isPlaying = false; // 强制回到视频开头,方便下次播放 this.video.pause(); // 只有非 loop 视频才重置时间,loop 视频让它在后台静音跑 if (!this.video.loop) { this.video.currentTime = 0; } // 静音只启动一次 this.video.muted = true; this.soundToggle.classList.remove("is-unmuted"); } // 自动播放(当进入视口时) autoPlay() { if (!this.hasAutoPlayed && this.config.autoplay) { this.hasAutoPlayed = true; this.play(); } } // 添加声音切换方法 toggleSound() { if (!this.video) return; // 切换静音状态 this.video.muted = !this.video.muted; // 更新 UI 状态 if (this.video.muted) { this.soundToggle.classList.remove("is-unmuted"); } else { this.soundToggle.classList.add("is-unmuted"); // 如果切换到有声且当前没在播,尝试播放(处理移动端静音自动播放后的手动开启) if (this.video.paused) { this.play(); } } } } // 页面主控制器 class HexoLivePhotoPage { constructor(config) { this.config = config; this.livePhotos = new Map(); this.observer = null; this.isWeixin = /micromessenger/i.test(navigator.userAgent); this.init(); } // 初始化 init() { this.detectLivePhotos(); // 检测是否为微信环境 // const isWeixin = navigator.userAgent // .toLowerCase() // .includes("micromessenger"); // 如果在微信环境中且禁用自动播放,则不设置Intersection Observer if (this.isWeixin && this.config.weixin_disable_autoplay) { return; } // 如果启用懒加载,设置Intersection Observer if (this.config.lazy_load) { this.setupIntersectionObserver(); } else if (this.config.autoplay) { // 如果不使用懒加载,直接自动播放所有 this.livePhotos.forEach((livePhoto) => livePhoto.autoPlay()); } } // 检测页面中的所有Live Photo容器 detectLivePhotos() { const containers = document.querySelectorAll(".live-photo-container"); containers.forEach((container) => { // 检查是否已经初始化过 if (!container.dataset.initialized) { const livePhoto = new HexoLivePhoto(container, this.config); this.livePhotos.set(container, livePhoto); container.dataset.initialized = "true"; } }); } // 设置Intersection Observer setupIntersectionObserver() { if (this.observer) { this.observer.disconnect(); } this.observer = new IntersectionObserver( (entries) => { entries.forEach((entry) => { const container = entry.target; const livePhoto = this.livePhotos.get(container); if (!livePhoto) return; if (entry.isIntersecting) { // 进入屏幕:自动播放 livePhoto.autoPlay(); if (!this.config.keep_observing) { this.observer.unobserve(container); } } else if (livePhoto.isPlaying) { // 移出屏幕时,必须强制停止播放 livePhoto.stop(); } }); }, { threshold: this.config.threshold || 0.1, rootMargin: "0px 0px 10% 0px", } ); this.livePhotos.forEach((_, el) => this.observer.observe(el)); } } // 当DOM加载完成后初始化 document.addEventListener("DOMContentLoaded", function () { if (window.HexoLivePhotoConfig && window.HexoLivePhotoConfig.enable) { window.hexoLivePhotoPage = new HexoLivePhotoPage(window.HexoLivePhotoConfig); } });