
凉蟾光满。桂子飘香远。 ------ 宋.谢逸 《点绛唇·金气秋分》
写在前面
最后有源码,可以先去下下来跑起来再看文章的细分,再决定看哪一部分,或许更好。一直认为有时候项目先跑起来,再去联想自己哪一部分比较模糊再具体去看,熟悉的就可看可不看。下一个vscode插件live-server
去本地跑起来。

目录
-
Banner目录搭建与素材的获取
-
Banner数据结构约定与使用
-
Banner元素DOM的属性编写
-
Banner页面鼠标事件&视觉差交互效果
内容
01. Banner目录搭建与素材的获取

根据控制台的元素可看出,是相同的class为layer
的div循环把素材循环有规律地放在指定位置,通过设置元素的transform
中translate
的x、y坐标来逐个把每个元素组成一幅会动的画,拆解成如下:
html
<div class="header-banner">
<div class="animated-banner">
// ...
// 🎨 这里循环放每个素材,汇成一幅画
</div>
</div>
css
body {
margin: 0;
padding: 0;
}
.header-banner {
position: relative;
z-index: 0;
min-height: 155px;
height: 9.375vw;
max-height: 240px;
background-color: #e3e5e7;
}
.animated-banner {
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;
}
打底底色框架效果:

这里值得注意的是,视频用了webm,也就是下面👇两个视频。


记得设置muted
true、loop
true、autoplay
true和style.objectFit = "cover"
,如下图。

02. Banner数据结构约定与使用
首先在index.html
文件里面全局搜索split_layer
这个单词,不需要用site_sucker去爬取页面或者保存当前页面,只需要打开控制台找Elements
那一栏,直接全部复制到一个sublime页面,去全局找就好:
得到的split_layer
这个东西是这样的:

打开console
那一栏:
- 赋值一个JSON.parse(xx)的值给a
- 然后copy(a),就可以在粘贴板上有这个数据对象了。(这个对象大有作用,因为我们基本不用看位置偏移诸如此类的配置项)
由于太大了,我只用截图来展示,如下:
arduino
const layers = {
version: "1",
layers: [
// ... 这里就是一个个小图对象
]
}

我们这里的话定义一个layers
承载这些数据。至于一个个素材的话,我们自己去下载下来,放在static
文件夹里。

主要代码: 通过循环这个layers数据(这个layers数据定义了资源路径
、scale
的initial
、rotate
、translate
、blur
、opacity
、name
等等初始数据),判断是视频的话就创建video
,如果是图片就创建img
js
layers.map((layer) => {
layer.resources.map((resource, resourceKey) => {
if (!/\.(webm|mp4)$/.test(resource.src)) {
// 🎨 创建图片
const imgElement = document.createElement('img')
imgElement.src = resource.src
layer.resources[resourceKey].el = imgElement
} else {
// 🎨 创建视频
const videoElement = document.createElement('video')
videoElement.muted = !0,
videoElement.loop = !0,
videoElement.autoplay = !0,
videoElement.src = resource.src,
videoElement.playsInline = !0,
videoElement.style.objectFit = 'cover',
layer.resources[resourceKey].el = videoElement
}
})
});
03. Banner元素DOM的属性编写
把各个图片的元素位置设置谁给你初始的偏移值,来调整它们本身应该待的位置。
我们观察一下B站首页控制台对应的每一个layer元素的dom结果,会发现处理了**一些style的属性值,一些width、height、translate(平移)、rotate(旋转)、scale(缩放)、opacity(透明度)**等等一些属性。

这里值得一提的是video的宽高的获取。
video宽高的获取,我们这里用了eachElement.addEventListener('loadedmetadata', () => { // ... })
这个方法来获取。从而再把视频的宽高给赋值上去。
得到的效果如下图:

04. Banner页面鼠标事件&视觉差交互效果
运用requestAnimationFrame
告诉浏览器我们要执行动画,并且要求浏览器再下次重绘之前调用指定的回调函数,更新动画。执行次数通常是每秒60次。不用了就把动画cancel掉。
requestAnimationFrame
在过去,我们执行动画一般用setTimeout或者setInterval去创建动画效果。但是这些方法存在一些问题。
setTimeout和setInterval
固定了动画的时间间隔,没有考虑到浏览器的刷新频率。可能导致动画在某些情况下出现撕裂、卡顿或者不连贯的问题
。
requestAnimationFrame
就可以解决这个问题,它接受一个回调函数作为参数
,这个回调函数会在下次浏览器刷新时调用
。也就意味着动画会跟浏览器的帧之间进行同步。


js
document.addEventListener("mouseleave", mouseLeaveFn), // 执行鼠标离开事件
window.addEventListener("mousemove", mouseMoveFn) // 执行鼠标移动时间
window.addEventListener("resize", resizeFn) // 根据浏览器窗口大小变化执行相应事件
最终效果:


下次b站再换主题,你就去谷歌控制台去找素材,然后下到本地
(主要是做了防盗链处理),下到本地也可以积累一季一季的素材,然后换layers数据结构即可
(这个去项目中的index.html)里面去找就可以了(上面有讲)。
总结
最终,话不多说,如果想下次有换主题,只需要需要layers这个数据(也就是一个一个元素的一些相关属性数据的大对象数组)即可!
祝您开发有乐趣。
☎️ 希望对大家有所帮助,如有错误,望不吝赐教,欢迎评论区留言互相学习。