前端开发,实现B站首页动态banner

点击上方 前端Q,关注公众号

回复加群,加入前端Q技术交流群

看B站这个动画banner好几个版本了,不知道是一个月更新一次新版动画,还是多少天更新一次(没有天天去看,但估算是一月更新一版UI,以后注意观察)。刚看到的时候很感兴趣,不像视频素材或者gif素材,就放一个视频上去,或者放一个动态画上去,这个是根据鼠标动而一个小范围地有规律有弧度地动,很少看过。

只是看过一些比如视觉差的类似这样的根据鼠标动而动的动画,

举例说明:

1、先前的github404动画图片层第轴动特效页面(最近改版了,没有动画效果了,以前我写有一篇文章就是关于github星球大战为主题的404错误页面,对鼠标哦🖱活动作出回应的相关代码,3d元素点睛);

github 404:

3e4e64cd1402bfc1d90be97c8d534c57.jpeg

2、视差引擎 parallax : [例子] (matthew.wagerfield.com/parallax/) 对光标的位置做出相应的反应。

parallax :

aa5bab86966b115a8f84a3e0ffba01d1.gif

3、滚动动画(视差、动画、交互) ScrollMagic

多伦多24小时环保干洗店、修鞋、洗衣叠服服务网站Alfred

83eb6b3b71f2d9fcc553178a2eca7026.gif

苹果vision产品页面

26fc15dba175e0920487845eba9a4a63.gif

太多这种类似视觉差效果的产品图了,就不一一举例了,有兴趣的伙伴自行搜索🔍...

前面讲到B站的首页的最上面一栏的根据鼠标的响应鼠标位置的视差效果。有的伙伴可能不怎么常去B站看(可能偶尔或者更多的是用手机端看),这边我贴一下效果,如下:

2c16a206d6b88228d0d07446e1598e51.gif

确实是想看一下是怎么做的。然后我就去搜,结果你可以去看看,印象很深的是一个人讲过(这里我就不讲了,可以搜搜看),反正就是提出了问题,问了观众是怎么做的,然后最后的结论是就是根据鼠标移动而移动。

"Talk is cheap, show me the code. —— Linus Torvalds" (直接翻译就是说话容易,给我展示代码),这个人的一句名言,也代表了他对实际代码和行动的重视,而不是停留口头的吹吹说说假大空。真正的生产力和进步是基于编写(或者集成他人的)代码的质量和效率,而不是单单谈论功能、空想事情的所有方式等等)。

有时候设计的时候概念很简单脱口而出,但是实际实现中需要做的工作是要多得多的(相信很多开发者在开发时候对这句话深有体会,说说说、说出花来、吹得天花乱坠,但是做,又是做不出个所以然来。所以说到一定程度,但好像没什么进展的时候,就得“多说无用,给我看你的行动”了,我笃信,无论是工作上还是人际关系上都是如此)。

所以,类似经常说的写作就是思考,那么我相信编程就是思考这句话也是同样富含逻辑和道理的。

接下来我们看一下是如何实现的

准备工作——素材

一共15张素材,15张素材构成一幅图。叫UI设计组小姐姐做。如若PS技术强,可以自己搞(先画出整体图,构想整体需要什么场景的、人和物和景,对了,然后一层一层关闭图层保存矢量图给前端),根据鼠标有规律(这里规律是指有范围、有移动偏移曲线、有透明度变化、有缩放变化等等地动)这个不知道是不是有产品经理给效果图给到UI小姐姐、给到前端去看最终效果,从而做出来的。

编程第一步:建一个html文件

不想着后面有多难,但至少这一步建文件我是会的,我正规点,建个文件夹,文件夹里建一个banner.html文件,再建一个static文件夹用来放素材。第一步就基本也错不到哪里去,大不了错了我再删,删了我再建。

该文用原生先写一遍,下一篇我再用vue或者react搞一遍,不喜欢看或者目前用不上原生的js来搞这个动画效果的可以到这里结束了,可以去B站首页自行体验体验。

建完文件的第一步:! + Tab

vscode !+Tab,完事,又进了一步。

2b308aafece67c45d46c1adb2a1cd474.jpeg

画底色

子内容重复循环的。那么,外框先画好。子内容接下来再想。

8e3cab9879218e91ba65710c8796e324.jpeg

12c1104c47b2788d832c1d59e7907854.jpeg

编写代码

观察,定义好数据结构

观察别人是怎么做的。其实这一步,应该从一开始就应该一直贯彻到末尾。只不过,做完上一步不知道下一步怎么做了,为了尽量可能接近结果,就先观察,把会做的,先做了。这里值得一提的是:控制台(控制台是一个很好的高分优秀答题者,有时候从控制台找答案会比我自己空想来得要完整和有用)。

1fcacb0bbd4f8b2c5c3580fcff947c04.jpeg

<div class="layer">
    <img 
        src="素材" 
        style="高度; 宽度; transform: translate(x, y) rotate(角度) scale(缩小或放大); opacity: 透明度;"
    >
</div>


// .
// .
// .
// 以此类推,15个素材元素,正好15个这样差不多的dom结构,(也可推测这是个数组,用来循环,开发如果所有东西都类似的东西手动一个个写人会疯掉且,即使愿意不怕累那也使不得,因为量大效率不高。所以这里用循环来搞)


// 而且如果下次要换不同的元素或者版块,改数据就好,不需要改其他。


// 那么数据结构是什么样子的呢?...

layers 数组数据结构:

const layers = [    {        resources: [            {                src: './static/4e7edb416c34eccc40f34d2b297524652685a9bb.png',                id: 0            }        ],
        scale: {
            initial: 0.6,
        },
        rotate: {},
        translate: {},
        blur: {},
        opacity: {
            wrap: "clamp",
        },
        name: '01 bg'
    },
    // 以此类推(有多少素材就有多少个对象,定义好素材地址、scale缩放、rotate旋转、translate偏移量、blur模糊度、opacity透明度、文件名备注): {}
]

一切以中心原点为定值:

01 bg

8b4e87e86117ff84715553d42baa2184.jpeg

641690dc455d298f7db83ec204dc0321.jpeg

13 远鸟

b421b7794ecf32e491f3e14f035a4279.jpeg

9ee4ba024bc633a8580cc25ca282be0c.jpeg

02 灯塔丛林

1a224757232c44174a2d0ecad1726822.jpeg

96f61de5cca1384be587958ca665e8bd.jpeg

03 底部海水

e2a310ba0835ea2b52623b209b427d47.jpeg

eb71b1b624bcd01968082c3fe3a8fcff.jpeg

04 鳄鱼a

a944719c1cb62498a6646ef77b8b8c7c.jpeg

1b3657373663b9f31d0f4bc6d889373a.jpeg

04 鳄鱼b

65f2f56edd8f02e231de91131ce28ccb.jpeg

9a3c9467dde8768dc8d1fea089d5abce.jpeg

05 左边鱼影

d8522300c1303e23e279f49a764010f5.jpeg

8401fbf5adab6fa5a4591025eb995ed4.jpeg

06 左边鱼群

3cf6e7db07d74bdd8d5fa5f72c2ec706.jpeg

434472b49ee3e6c3a05c19401145b459.jpeg

07 右边鱼

8c20bb9b99d02f5be272e1b810e75561.jpeg

bb51c1ea2067f4b7cc9bf3bc2253f017.jpeg

08 右边鸟

758b401b43cc185f3daeca54a59590c8.jpeg

f330b9abf988f31115017ddee07bf4eb.jpeg

09 中间

6bad3b52ce12b0d83903bab55a4f6bbe.jpeg

6c06a42f6e33bdd4efcc0dcc0f897da9.jpeg

11 33

a992c4e9240a56ed8ca1016748c957c0.jpeg

5ed9ff91eb6d18cce246f26a2f058a20.jpeg

10 水面

d6fd6cbfbcccd5d40f42d09945943faf.jpeg

403b0abdea2349cd76e48b9f9057a72a.jpeg

12 近鸟

50bfb02a96edadd2929fad56d6d85b36.jpeg

e4af0afb604b7e5a36fad494d3dee326.jpeg

14 两侧

ec6a6a2634c4bf5a5f7d8ce8dd688c87.jpeg

dd63ca9a75aff379ed502708650d8b8d.jpeg


给每个素材定宽高

这一步就是根据上面的数据结果,给每个素材设置一下宽高。其中要看scale的值和相对它们来说最大的外框.animated-banner的高度来响应式地对每个素材的宽高进行处理。

affb201107d4796e0628254fd0f290a2.jpeg

(注:如若看不清,右击在新标签页打开图片查看)

给每个元素加个div

这一步就直接给每个img加个div。class为layer

css 需要加上这个layer的样式:

.layer {
  position: absolute;
  left: 0;
  top: 0;
  height: 100%;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

js 需要加上:

const divElementArr = layers.map(() => {
    const divElement = document.createElement('div')
    divElement.classList.add('layer')
    banner.appendChild(divElement)
    return divElement
})

最后得到的是一个数组,每一个(这里有15个)元素class为layer的div。然后append到.animated-banner最大boss上。

01dd9f488626db28f940e38ea94eeff6.jpeg

append素材到layer的div上

append素材元素,追加上去,代码如下:

layers.map((layer, layerKey) => {
    const layerElement = layer.resources[0].el
    divElementArr[layerKey].appendChild(layerElement)
})

这个时候就得到效果图如下:

acc5657fa94fe675485c9f01af9a35f5.jpeg

可以看到,所有的元素都以正中心排布(原因就是上面的css中相对定位所有都center水平居中垂直居中)。

那这个时候就说了,下一步是不是根据数据结构,给每个元素距离正中心偏移多少设置了。没错的。

初始样式设置 以及 每个元素距离正中心偏移排布

初始样式设置

a738ecb0aa7a30903c0bf83f22717964.jpeg

// 鼠标指针相对窗口边缘水平坐标 左还是右,左进则是正数比率,右进则是负数比率
let relativeX = 0;

每个元素距离正中心偏移排布

eaaf622383a06f293730fac835083f12.jpeg

一开始加载元素的偏移排布

85f76ea8b5beef12aa4ec410a962e94f.jpeg

鼠标监听事件

20e7599b1d8bc4fecf248cf1df24b406.jpeg

效果图

76098cacba1bd036fbad50b5065f783a.gif

总结

此次文章研究B站的动图如何实现(实现transform中的translate如何如何一比一还原,篇幅太大缩放大小、透明度,以及moveleave还没仔细讲解),但基本上同一原理,这里难点重点是贝塞尔曲线,元素按曲线运动以及左右移动换鳄鱼图,以及透明度的问题。

完成上面的点(至于代码随后会分享出)

有空出用vue和react实现。

作者:盏灯
链接:https://juejin.cn/post/7275576084128350248

abdd48124c3741b2b49ebe57e20bcf21.png

往期推荐

中美程序员不完全对比,太真实了。。。

1fe9c58be53547d8ac0f78a43025169f.png

两行CSS让长列表性能渲染提升7倍!

e5a351f8d0a9c61a7dcf361214668bf5.png

周爱民:告前端同学书

4cdafeaeedf5a1a4c1de8f04b3ea0ccb.png


最后

  • 欢迎加我微信,拉你进技术群,长期交流学习...

  • 欢迎关注「前端Q」,认真学前端,做个专业的技术人...

25c9affb3cff40b8723e29860f3988aa.jpeg

6be3531adea3fe7862d29ce6d7c713f5.png

点个在看支持我吧

0ed7d446e1ad2c9e7016258f9e48d8d7.gif

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值