实现 B 站首页头部效果

Clloz · · 1,659次浏览 ·

前言

今天偶然发现 B 站首页的头部有一个移动鼠标,背景移动并且透明度变化,也带有一点视差滚动的效果。同时小人的眼睛隔一段时间眨一下。我觉得挺有趣就自己实现了一下。

实现效果:点击查看 Demo

实现思路

分析一下这个效果大概就是两个部分。第一个部分是人物的眨眼,这个我用的嵌套的定时器实现。第二个部分就是鼠标移动改变图片的位置和透明度,这个用鼠标事件解决。

眨眼效果

眨眼效果的其实就是几张图片的连续播放。但是需要注意的是,眨眼的动作是非常快的,整个动作要三个状态,睁眼,半睁眼,闭眼,我们需要四张图片循环即可。

由于眨眼的帧之间的间隔和两次眨眼之间的间隔是不同的,我们需要嵌套定时器。外部的就是控制多久眨眼一次,内部的就是眨眼的几个帧的切换。对于定时器的嵌套中的一些细节可以看我的另一篇文章:定时器的一些思考。最后的代码大致如下:

let img = this.layers[anime.index].querySelector('img');

setInterval(() => {
    let index = 0;

    let blink = setInterval(() => {
        img.src = `./images/${anime.path}/${index % anime.length}.png`;
        index++;
        if (index === anime.length + 1) clearInterval(blink);
    }, 100);
}, 5000);

这里有一个我没有解决的问题,我的图片切换是用改变 imgsrc 来实现的。这样会出现一个问题,每次改变 src 浏览器都会发送新的请求。而且由于我们的这种行为在浏览器看来很怪异,可能会被 cancel 掉(关于浏览器请求的 cancel 可以参考这篇文章 浏览器你为什么要干掉我的请求?。这就导致了我们本地运行可能没问题,但是到线上访问动画就时灵时不灵了。我看 B 站的实现似乎是将 img 这个元素替换了,源码混淆过,看着着实吃力,放弃了。这里应该是一个知识盲区,我尝试了替换元素,但是并没有效果 :dizzy_face: 。这里暂时只能留个坑,等以后知道怎么解决了再来填。


segmentfault 上提问后,Fractal 给出的回答是预先生成好 img 元素,放到一个数组中,然后定时器内替换即可。我是用 cloneNodereplaceChild 两个方法进行创建和切换的。这样就基本实现了原先要的效果了。以后遇到这种加载切换问题应该也可以用同样的逻辑解决。

鼠标事件

第二个效果就是移动鼠标图片会跟着移动,然后透明度变化,最后的效果就是感觉随着鼠标的移动,我们的视角也发生变化的感觉。这部分的实现就是用三个鼠标事件,mouseover, mousemove, mouseout。然后改变元素的 style 对象中的属性即可,并没有什么复杂的逻辑。需要注意的是,mouseout 之后我们要将元素的状态还原,同时解绑 mousemovemouseout 事件。

总结

完整的代码在 Github。运行方法为 npm install 之后运行 npx webpack-dev-server 然后打开 index.html 即可。


Clloz

人生をやり直す

1 个评论

BobMaster · 2020年10月26日 - 下午9:25

好棒的效果,继续加油大佬!

发表评论

电子邮件地址不会被公开。 必填项已用*标注

我不是机器人*

 

00:00/00:00