Files
ksapi/newKs/src/public/index.html
2026-06-01 00:21:44 +08:00

296 lines
8.2 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>视频圆形放大镜(最终流畅版)</title>
<script src="./lazyload.min.js"></script>
<style>
* {
margin: 0;
padding: 0;
list-style: none;
font-size: 0;
line-height: 0;
background: #000;
}
ul {
display: flex;
flex-wrap: wrap;
}
ul li {
width: 20%;
background: #000;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
position: relative;
overflow: hidden;
}
ul li .lazy {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
pointer-events: auto;
}
/* 放大镜样式 */
.video-magnifier {
position: fixed;
width: 400px;
height: 400px;
border-radius: 50%;
border: 3px solid rgba(255, 255, 255, 0.9);
box-shadow: 0 0 30px rgba(0, 0, 0, 0.6), 0 0 0 4px rgba(0, 0, 0, 0.3);
pointer-events: none;
overflow: hidden;
z-index: 10000;
display: none;
backdrop-filter: blur(10px);
transition: left 0.02s ease-out, top 0.02s ease-out;
background: transparent !important;
}
.video-magnifier video {
position: absolute;
width: 100%;
height: 100%;
background: transparent !important;
}
</style>
</head>
<body>
<ul></ul>
<!-- 放大镜容器 -->
<div class="video-magnifier" id="magnifier">
<video id="magnifierVideo" muted loop playsinline></video>
</div>
<script>
let page = "";
const defaultSpeed = 2;
let scrollSpeed = defaultSpeed;
let scrollLock = false;
let handlerId = null;
let currentVideo = null;
const ul = document.querySelector("ul");
const magnifier = document.getElementById('magnifier');
const magnifierVideo = document.getElementById('magnifierVideo');
let hoveredVideo = null;
let magnifierEnabled = false;
// ==================== 流畅缩放配置 ====================
const minMagnifierSize = 400; // 最小尺寸
const maxMagnifierSize = 600; // 最大尺寸(防卡顿)
const stepSize = 100; // 每次增减 40px流畅不卡
let magnifierSize = 400;
const scale = 4;
// 记录当前鼠标位置
let currentMouseX = 0;
let currentMouseY = 0;
let lazyLoadInstance = null;
// 实时记录鼠标位置
document.addEventListener('mousemove', (e) => {
currentMouseX = e.clientX;
currentMouseY = e.clientY;
});
const initLazyLoad = () => {
if (lazyLoadInstance) return;
lazyLoadInstance = new LazyLoad({
threshold: 300,
elements_selector: ".lazy",
unobserve_entered: true,
cancel_on_exit: true,
});
};
const getHttpData = async () => {
if (scrollLock) return;
try {
scrollLock = true;
const res = await fetch(`http://127.0.0.1:3030?pcursor=${page}`);
const data = await res.json();
scrollLock = false;
render(data);
} catch (err) {
scrollLock = false;
console.error("数据加载失败", err);
}
};
const render = (data) => {
const { feeds, pcursor } = data;
page = pcursor;
if (!feeds || feeds.length === 0) return;
const fragment = document.createDocumentFragment();
feeds.forEach(item => {
const li = document.createElement("li");
const video = document.createElement("video");
video.className = "lazy";
video.preload = "metadata";
video.muted = true;
video.loop = true;
video.playsInline = true;
video.author = `https://www.kuaishou.com/profile/${item.author.id}`;
const posterUrl = item.photo.animatedCoverUrl || item.photo.coverUrl;
video.poster = posterUrl;
video.dataset.src = item.photo.photoUrls[0]?.url || "";
li.appendChild(video);
fragment.appendChild(li);
});
ul.appendChild(fragment);
if (lazyLoadInstance) lazyLoadInstance.update();
if (!handlerId) startScroll();
};
const startScroll = () => {
const scrollStep = () => {
window.scrollBy(0, scrollSpeed);
handlerId = requestAnimationFrame(scrollStep);
};
handlerId = requestAnimationFrame(scrollStep);
};
const stopScroll = () => {
cancelAnimationFrame(handlerId);
handlerId = null;
};
const toggleScroll = () => {
handlerId ? stopScroll() : startScroll();
};
document.onclick = toggleScroll;
// 强制更新放大镜到当前鼠标位置
function updateMagnifierToMouse() {
if (!magnifierEnabled) return;
magnifier.style.width = magnifierSize + 'px';
magnifier.style.height = magnifierSize + 'px';
const element = document.elementFromPoint(currentMouseX, currentMouseY);
if (!element || element.tagName !== 'VIDEO') {
magnifier.style.display = 'none';
return;
}
const video = element;
if (hoveredVideo !== video) {
hoveredVideo = video;
magnifierVideo.src = video.dataset.src || video.src;
magnifierVideo.play().catch(() => { });
}
magnifier.style.display = 'block';
magnifier.style.left = (currentMouseX - magnifierSize / 2) + 'px';
magnifier.style.top = (currentMouseY - magnifierSize / 2) + 'px';
const rect = video.getBoundingClientRect();
const relativeX = (currentMouseX - rect.left) / rect.width;
const relativeY = (currentMouseY - rect.top) / rect.height;
const offsetX = -(relativeX - 0.5) * rect.width * scale;
const offsetY = -(relativeY - 0.5) * rect.height * scale;
magnifierVideo.style.transform = `scale(${scale}) translate(${offsetX}px, ${offsetY}px)`;
}
document.onkeydown = (e) => {
const { keyCode } = e;
// F键开关放大镜
if (keyCode === 70) {
e.preventDefault();
magnifierEnabled = !magnifierEnabled;
if (magnifierEnabled) {
updateMagnifierToMouse();
} else {
magnifier.style.display = 'none';
magnifierVideo.pause();
magnifierVideo.src = '';
hoveredVideo = null;
}
}
// + 键:每次增加 40px最大 800px
if (keyCode === 107 || keyCode === 187) {
e.preventDefault();
if (magnifierSize < maxMagnifierSize) {
magnifierSize += stepSize;
updateMagnifierToMouse();
}
}
// - 键:每次减少 40px最小 400px
if (keyCode === 109 || keyCode === 189) {
e.preventDefault();
if (magnifierSize > minMagnifierSize) {
magnifierSize -= stepSize;
updateMagnifierToMouse();
}
}
// 其他原有按键
if (keyCode === 79) { e.preventDefault(); if (currentVideo) open(currentVideo.author); }
if (keyCode === 32) { e.preventDefault(); toggleScroll(); }
if (keyCode === 82) { e.preventDefault(); scrollSpeed = defaultSpeed; }
if (keyCode === 40) { e.preventDefault(); scrollSpeed += 2; }
if (keyCode === 38) { e.preventDefault(); scrollSpeed > defaultSpeed && (scrollSpeed -= 2); }
};
let scrollTimer = null;
window.onscroll = () => {
if (scrollLock) return;
clearTimeout(scrollTimer);
scrollTimer = setTimeout(() => {
const scrollTop = window.scrollY;
const clientHeight = window.innerHeight;
const scrollHeight = document.documentElement.scrollHeight;
if (clientHeight + scrollTop >= scrollHeight - 300) {
getHttpData();
}
}, 150);
};
ul.addEventListener('mousemove', (e) => {
if (!magnifierEnabled) return;
updateMagnifierToMouse();
});
ul.addEventListener('mouseleave', () => {
if (!magnifierEnabled) return;
magnifier.style.display = 'none';
magnifierVideo.pause();
magnifierVideo.src = '';
hoveredVideo = null;
}, true);
ul.addEventListener("mouseenter", (e) => {
if (e.target.tagName === "VIDEO") {
e.target.readyState >= 2 && e.target.play();
currentVideo = e.target;
}
}, true);
initLazyLoad();
getHttpData();
</script>
</body>
</html>