原生js模仿B站首页之冬季Banner的实现
实现效果

图层效果分析
Banner区总共七张图片加一个无限循环的视频,随着鼠标的移动,呈现出不同时间段的效果。在鼠标的移动的过程中,给各个图片设置相应的位移和透明度来实现视觉效果的转换。整个Banner区的效果分为三个时段:早上、下午和晚上。默认显示的是下午的图片,鼠标由左到右会慢慢显示出晚上的效果,由右到左则慢慢显示早上的效果。
实现步骤
按B站布局方式放置好图片和视频
<div class="animate-box">
<div class="layer"><img src="https://cdn.jsdelivr.net/gh/Zhangzyb/BiliBili@1.0/images/0.jpg"></div>
<div class="layer"><img src="https://cdn.jsdelivr.net/gh/Zhangzyb/BiliBili@1.0/images/1.jpg"></div>
<div class="layer"><img src="https://cdn.jsdelivr.net/gh/Zhangzyb/BiliBili@1.0/images/2.png"
style="width: 2400px;height: 184px;transform: translate(40px, 16px) rotate(10deg);"></div>
<div class="layer">
<video loop="loop" src="https://cdn.jsdelivr.net/gh/Zhangzyb/BiliBili@1.0/images/video.webm" style="object-fit: cover; opacity: 0;" autoplay="autoplay"
muted="muted"></video>
</div>
<div class="layer"><img src="https://cdn.jsdelivr.net/gh/Zhangzyb/BiliBili@1.0/images/3.png" style="opacity: 0;"></div>
<div class="layer"><img src="https://cdn.jsdelivr.net/gh/Zhangzyb/BiliBili@1.0/images/4.png" style="filter: blur(2px);"></div>
<div class="layer"><img src="https://cdn.jsdelivr.net/gh/Zhangzyb/BiliBili@1.0/images/5.png" style="filter: blur(2px);"></div>
<div class="layer"><img src="https://cdn.jsdelivr.net/gh/Zhangzyb/BiliBili@1.0/images/6.png" style="opacity: 0; filter: blur(5px);"></div>
<canvas id="canvas" width="1519" height="155"></canvas>
</div>
<style>
.animate-box {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
overflow: hidden;
}
.layer {
position: absolute;
left: 0;
top: 0;
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.layer img,
video {
height: 155px;
width: 2016px;
transform: scale(1) translate(0px, 0px) rotate(0deg);
filter: blur(0px);
opacity: 1;
}</style>
使用js的鼠标事件完成效果
const box = document.querySelector('.animate-box');
let imgs = document.querySelectorAll('.layer img');
let video = document.querySelector('.layer video');
let initPosition; // 进入盒子的初始位置
let mouseMove; // 鼠标在盒子内的移动距离
let commonMove; // 背景图、视频和水汽的移动距离
let branchesMove; // 树枝移动距离
let snowMove; // 雪球的移动距离
let snowRotate; // 雪球的旋转度
// 鼠标从左到右
let videoOpacity; // 视频移动过程中的透明度
let steamOpacity; // 玻璃窗上的水汽移动过程中的透明度
let nightBranchOpacity; // 晚上树枝的透明度
// 鼠标从右到左
let afternoonImgOpacity; // 下午的背景图片透明度
let snowOpacity; // 雪球的透明度
let afternoonBranchOpacity; // 下午的树枝透明度
box.addEventListener('mouseenter', (e) => {
initPosition = e.pageX;
})
box.addEventListener('mousemove', (e) => {
mouseMove = initPosition - e.pageX; // 小于0则表示鼠标再向右移动,否则鼠标在向左移动
commonMove = mouseMove / 15;
branchesMove = mouseMove / 11;
snowMove = mouseMove / 5.5;
snowRotate = mouseMove / 307;
// 背景图片和视频的移动
video.style.transform = 'translate(' + commonMove + 'px,0px)'; // 视频
imgs[0].style.transform = 'translate(' + commonMove + 'px,0px)'; // 早上的背景图片
imgs[1].style.transform = 'translate(' + commonMove + 'px,0px)'; // 下午的背景图片
imgs[3].style.transform = 'translate(' + commonMove + 'px,0px)'; // 水汽
// 雪球的位移
imgs[2].style.transform = 'translate(' + (40 + snowMove) + 'px,' + (16 - mouseMove / 220) + 'px) rotate(' + (10 + snowRotate) + 'deg)';
// 树枝的移动
// for (let i = 4; i < 7; i++) {
// imgs[i].style.transform = 'translate(' + branchesMove + 'px,0px)';
// }
imgs[4].style.transform = 'translate(' + branchesMove + 'px,0px)';
imgs[5].style.transform = 'translate(' + branchesMove + 'px,0px)';
imgs[6].style.transform = 'translate(' + branchesMove + 'px,0px)';
if (mouseMove < 0) { //鼠标向右移动
// 在鼠标向右移动的过程中,视频、水汽和晚上的树枝的透明度均经过 0 ~ 1 的变化,其余不变
// 并且三个元素的透明度变化速度各不相同
videoOpacity = Math.abs(commonMove / 100) * 3; // 视频的透明度
steamOpacity = Math.abs(commonMove / 100) * 1.5; // 水汽的透明度
nightBranchOpacit = Math.abs(branchesMove / 100) * 2.2; // 晚上树枝的透明度
// 透明度超过 1 时均赋值为 1
video.style.opacity = videoOpacity >= 1 ? 1 : videoOpacity;
imgs[3].style.opacity = steamOpacity >= 1 ? 1 : steamOpacity;
imgs[6].style.opacity = nightBranchOpacit >= 1 ? 1 : nightBranchOpacit;
}
else { // 鼠标向左移动
// 鼠标向左移动过程中,下午的图片、雪球的图片和下午的树枝的透明度均经过 1 ~ 0 的变化,其余不变
afternoonImgOpacity = 1 - (commonMove / 100) * 4;
snowOpacity = 1 - (commonMove / 100) * 2.4;
afternoonBranchOpacity = 1 - (commonMove / 100) * 3.2;
// 透明度低于 0 时均赋值为 0
imgs[1].style.opacity = afternoonImgOpacity <= 0 ? 0 : afternoonImgOpacity; // 下午的图片透明度
imgs[2].style.opacity = snowOpacity <= 0 ? 0 : snowOpacity; // 雪球图片透明度
imgs[5].style.opacity = afternoonBranchOpacity <= 0 ? 0 : afternoonBranchOpacity; // 下午的树枝透明度
}
})
box.addEventListener('mouseleave', () => {
// 鼠标从左到右移动离开图片区
// 位移距离还原
video.style.transform = 'translate(0,0)';
imgs[0].style.transform = 'translate(0,0)';
imgs[1].style.transform = 'translate(0,0)';
imgs[2].style.transform = 'translate(40px, 16px) rotate(10deg)';
imgs[3].style.transform = 'translate(0,0)';
imgs[4].style.transform = 'translate(0,0)';
imgs[5].style.transform = 'translate(0,0)';
imgs[6].style.transform = 'translate(0,0)';
// 透明度还原
video.style.opacity = 0;
imgs[3].style.opacity = 0;
imgs[6].style.opacity = 0;
// 鼠标从右到左离开图片区
// 透明度还原
imgs[1].style.opacity = 1; // 下午的背景图片
imgs[2].style.opacity = 1; // 雪球图片
imgs[5].style.opacity = 1; // 下午的树枝图片
})
Canvas完成雪花效果
// 雪花特效
let canvas = document.querySelector('#canvas');
let ctx = canvas.getContext('2d');
canvas.style.position = 'absolute';
canvas.style.top = 0;
canvas.style.left = 0;
class Snow {
constructor(canvas) {
this.x = 0;
this.y = 0;
this.vy = 0;
this.radius = 0;
this.alpha = 0.5;
this.canvas = canvas;
this.ctx = canvas.getContext('2d');
this.init();
}
init() {
this.x = Math.random() * this.canvas.width;
this.vy = 0.3 + Math.random() * 1;
this.radius = 1 + Math.random() * 3;
this.alpha += Math.random() * 0.5;
this.ctx.fillStyle = '#ffffff';
}
draw() {
this.ctx.globalAlpha = this.alpha;
this.ctx.beginPath();
this.ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
this.ctx.closePath();
this.ctx.fill();
}
}
let snows = []
let cnt = 0;
function moveSnow(snow) {
snow.y += snow.vy;
if (snow.y >= canvas.height) {
snow.y = 0
}
snow.draw();
}
function drawSnow() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
cnt++;
if (cnt <= 60) {
let snow = new Snow(canvas);
snows.push(snow);
}
snows.forEach(moveSnow);
window.requestAnimationFrame(drawSnow);
}
window.requestAnimationFrame(drawSnow);

浙公网安备 33010602011771号