的控制台主题_(万字长文)从 B 站的秋季主题中学习 “图层组合动画”

从 B 站的秋季主题中学习 “图层组合动画”

0286e0141bf9f4f377b4d63c3b4b3904.png

众所周知,B 站 是个适合学习的好网站,我们团队的小伙伴也是经常上 B站 学习。

某一天在 B站 学习的时候,发现 B站 已经开启了秋季主题,并且在头图的这个交互上还内有乾坤。随着我们的鼠标变换位置,头图也跟随着我们的鼠标位置进行变换,配上秋季主题,显得特别治愈。(如下图)

0286e0141bf9f4f377b4d63c3b4b3904.png

小编对这个交互也是挺感兴趣的,那接下来我们直接进入主题,来试着实现这种动画效果吧!

原理分析

我们先进行实现原理分析,打开控制台,可以发现这个效果是通过几个图层变换位置和高斯模糊来实现的(如下图)

34994c652d336ad0319dc368e8cc89d2.png
image

除此之外,还有个小女孩的 眨眼 特效,是通过切换图片来实现的。所以我们实现的步骤分解为四步:

  1. 获取对应的图片;
  2. 将图片按照效果图,摆放在对应的位置,设置默认的高斯模糊;
  3. 通过切换图片制作 眨眼 特效;
  4. 根据鼠标位置切换图片位置和高斯模糊;

那我们遵循上面的步骤,开始制作吧!

获取图片

首先,我们打开控制台(F12),在控制台输入下面这行代码来获取图片。

var images = document.querySelectorAll(".animated-banner .layer img");
var urlList = [].slice.call(images).map((item) => item.src);
console.log(JSON.stringify(urlList, null, 2));
1c489250fd2da4f07c9dda7cec65e2d9.png
image

如上图所示,我们将这几张图片下载到自己的电脑中(如下图)

9733d7b232aa130d720eb47d04153165.png
image

还有个动画轮播图,我们使用下面这行代码来获取不同的几张图片。

var animateImgList = [];
setInterval(() => {
  var imgSrc = document.querySelector(
    ".animated-banner >.layer:nth-child(2) img"
  ).src;
  if (!animateImgList.includes(imgSrc)) {
    console.log(imgSrc);
    animateImgList.push(imgSrc);
  }
}, 200);
9b7d9b0caf5689a55ed97fc370389737.png
image

如上图所示,我们可以得到几张不同状态的图片,我们下载到自己的电脑里即可。

摆放图片

我们下载的几张图片都是 png 格式的,我们可以使用定位将其堆叠到一起。

直接新建一个 index.html,填充内容如下:

html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1.0" />
    <title>Documenttitle>
  head>
  <style>
    * {margin: 0;padding: 0;
    }.img-list {width: 100%;min-width: 1000px;height: 155px;position: relative;overflow: hidden;
    }.img-list .layer {position: absolute;left: 0;top: 0;width: 100%;height: 100%;display: flex;align-items: center;justify-content: center;
    }style>
  <body>
    <section class="img-list">
      <div class="layer">
        <img width="3000" height="250" src="./assets/1.png" alt="" />
      div>
      <div class="layer">
        <img width="1800" height="165" src="./assets/2_1.png" alt="" />
      div>
      <div class="layer">
        <img width="3000" height="250" src="./assets/3.png" alt="" />
      div>
      <div class="layer">
        <img width="1800" height="150" src="./assets/4.png" alt="" />
      div>
      <div class="layer">
        <img width="1800" height="165" src="./assets/5.png" alt="" />
      div>
      <div class="layer">
        <img width="1950" height="178" src="./assets/6.png" alt="" />
      div>
    section>
  body>
html>

上面做了简单的图片排列,实现的效果如下图所示:

a18bd39461e24c41c5f182e87770fb98.png
image

从上图可以看出,我们将多张图片堆叠后,已经有初步的雏形了,接下来我们来设置默认的高斯模糊吧。

由于我们的位置偏移和高斯模糊在后面需要涉及到交互,所以我们直接使用 JS 进行设置,这里我们借助一下 Jquery,在 body 后引入 jquery,然后写入我们的 javascript 脚本(如下)。

<script src="https://cdn.bootcdn.net/ajax/libs/jquery/1.10.0/jquery.js">script>
<script>const imgList = $(".img-list .layer img");// 默认的位置偏移与高斯模糊值const defaultStyles = [
    { translateX: 0, translateY: 0, blur: 4 },
    { translateX: 0, translateY: 0, blur: 0 },
    { translateX: -50, translateY: 0, blur: 1 },
    { translateX: 0, translateY: 4.2, blur: 4 },
    { translateX: 0, translateY: -1.8, blur: 5 },
    { translateX: 0, translateY: 0, blur: 6 },
  ];function setDefaultImgStyle() {for (let i = 0; i       const imgItem = imgList[i];const defaultStyle = defaultStyles[i];const { translateX, translateY, blur } = defaultStyle;// 设置位置偏移以及高斯模糊
      $(imgItem).css({// 位置偏移transform: `translate(${translateX}px, ${translateY}px)`,// 高斯模糊filter: `blur(${blur}px)`,
      });
    }
  }
  setDefaultImgStyle();script>

在设置好了位置偏移和高斯模糊后,我们的静态页面已经和效果图完全一致了(如下图)。

cb819c821affba0f60ec75e330b6cac7.png
image

制作眨眼特效

我们的静态页面已经制作的差不多了,接下来我们来用 JS 简单实现 眨眼 特效吧。

这个比较简单,我们只需要设置一个定时器,每 3 秒切换一次图片集即可,代码实现如下:

function setShakeAnimation() {
  // 第二张小女孩图片
  const imgGirl = $(".img-list .layer:nth-child(2) img");

  // 每 3 秒眨一次眼睛
  setInterval(() => {
    // 半闭眼
    $(imgGirl).attr("src", "./assets/2_2.png");

    // 100 毫秒后完全闭上眼眼睛
    setTimeout(() => {
      $(imgGirl).attr("src", "./assets/2_3.png");
    }, 100);

    // 300 毫秒后半睁开眼睛
    setTimeout(() => {
      $(imgGirl).attr("src", "./assets/2_2.png");
    }, 300);

    // 400 毫秒后完全睁开眼睛
    setTimeout(() => {
      $(imgGirl).attr("src", "./assets/2_1.png");
    }, 400);
  }, 3000);
}
setShakeAnimation();

然后,我们来看看我们的 眨眼 特效吧!(如下图)

557e097ed07184f125c430eb101c0767.gif
image

如上图所示,我们的 眨眼 特效已经可以做到以假乱真啦!

动态交互

最后,我们来为我们的图层合集添加上交互效果吧!

我们从 B站 原有的交互中可以发现,当我们把鼠标放上去左右移动时,图片发生了位置和高斯模糊度的变化。所以我们先把鼠标移动的事件监听加上,代码实现如下:

// 屏幕宽度
const width = document.body.clientWidth;
// 鼠标进入的事件
$(".img-list").mouseenter((e) => {
  // 鼠标离开时解除事件监听,并重置状态
  $(".img-list").mouseleave(() => {
    setDefaultImgStyle();
    $(".img-list").off("mousemove");
    $(".img-list").off("mouseleave");
  });

  // 鼠标进入时记录位置
  const originalX = e.pageX;
  $(".img-list").mousemove((e) => {
    // 鼠标移动时记录位置
    const currentX = e.pageX;
    // 根据屏幕宽度和移动距离,计算移动的比例
    const offsetRatio = (currentX - originalX) / width;
    // 鼠标左移
    if (offsetRatio 0) {
      setLeftImgStyle(Math.abs(offsetRatio));
      // 鼠标右移
    } else {
      setRightImgStyle(offsetRatio);
    }
  });
});

接下来,我们经过大致测量一下后会发现,高斯模糊变化的效果如下表所示。

图片序号初始值(高斯模糊值)从最右侧到最左侧(高斯模糊值)从最左侧到最右侧(高斯模糊值)
144 -> 04 -> 8
200 -> 100 -> 8
311 -> 51 -> 4
444 -> 134 -> 0 -> 4
555 -> 145 -> 0 -> 4
666 -> 126 -> 0

位置变化的效果如下表所示。

图片序号初始值(X 轴位置)从最右侧到最左侧(X 轴位置)从最左侧到最右侧(X 轴位置)
1000
20-99
3-50-8021
40-3635
50-7877
60-9796

根据上面两张表,我们就可以开始写代码啦,代码实现如下:

// 鼠标左移后的最终目标位置
const leftStyles = [
  {
    translateX: 0,
    translateY: 0,
    blur: 0,
  },
  {
    translateX: -9,
    translateY: 0,
    blur: 10,
  },
  {
    translateX: -80,
    translateY: 0,
    blur: 5,
  },
  {
    translateX: -36,
    translateY: 4.2,
    blur: 13,
  },
  {
    translateX: -78,
    translateY: -1.8,
    blur: 14,
  },
  {
    translateX: -97,
    translateY: 0,
    blur: 12,
  },
];

function setLeftImgStyle(offsetRatio) {
  for (let i = 0; i     const imgItem = imgList[i];
    const {
      translateX: defaultTranslateX,
      translateY: defaultTranslateY,
      blur: defaultBlur,
    } = defaultStyles[i];
    const leftStyle = leftStyles[i];
    // 根据移动比例计算最终坐标和高斯模糊值
    const translateX =
      (leftStyle.translateX - defaultTranslateX) * offsetRatio +
      defaultTranslateX;
    const blur = (leftStyle.blur - defaultBlur) * offsetRatio + defaultBlur;

    // 设置位置偏移以及高斯模糊
    $(imgItem).css({
      // 位置偏移
      transform: `translate(${translateX}px, ${defaultTranslateY}px)`,
      // 高斯模糊
      filter: `blur(${blur}px)`,
    });
  }
}

// 鼠标右移后的最终目标位置
const rightStyles = [
  {
    translateX: 0,
    translateY: 0,
    blur: 8,
  },
  {
    translateX: 9,
    translateY: 0,
    blur: 8,
  },
  {
    translateX: 21,
    translateY: 0,
    blur: 4,
  },
  {
    translateX: 35,
    translateY: 4.2,
    blur: [0, 4],
  },
  {
    translateX: 77,
    translateY: -1.8,
    blur: [0, 4],
  },
  {
    translateX: 96,
    translateY: 0,
    blur: 0,
  },
];

function setRightImgStyle(offsetRatio) {
  for (let i = 0; i     const imgItem = imgList[i];
    const {
      translateX: defaultTranslateX,
      translateY: defaultTranslateY,
      blur: defaultBlur,
    } = defaultStyles[i];
    const rightStyle = rightStyles[i];
    let rightBlur = rightStyle.blur;
    let blur = defaultBlur;
    // 根据移动比例计算最终坐标和高斯模糊值
    const translateX =
      (rightStyle.translateX - defaultTranslateX) * offsetRatio +
      defaultTranslateX;
    if (Array.isArray(rightBlur)) {
      const targetBlur = offsetRatio 0.5 ? rightBlur[0] : rightBlur[1];
      const ratio =
        offsetRatio 0.5 ? offsetRatio * 2 : (offsetRatio - 0.5) * 2;
      const currentBlur = offsetRatio 0.5 ? defaultBlur : rightBlur[0];
      blur = (targetBlur - currentBlur) * ratio + currentBlur;
    } else {
      blur = (rightBlur - defaultBlur) * offsetRatio + defaultBlur;
    }
    // 设置位置偏移以及高斯模糊
    $(imgItem).css({
      // 位置偏移
      transform: `translate(${translateX}px, ${defaultTranslateY}px)`,
      // 高斯模糊
      filter: `blur(${blur}px)`,
    });
  }
}

在上面的代码实现中,我们在鼠标左移右移的过程中添加了图片位置偏移与高斯模糊值,最后我们实现的效果就和 B站 的原版很相近了!(如下图)

0286e0141bf9f4f377b4d63c3b4b3904.png

好了,大功告成啦!

总结

经过简单的步骤分析,我们将几张图片组合起来就模拟出了 B站 的秋季主题效果啦!

这个案例是在某次学习(发呆)的时候发现 B站 的秋季主题挺有意思的,这里分享出来给大家,用几张图片组合出这么一个创意交互,也是挺有趣的~

最后,附上 源码地址

转载自:https://github.com/a1029563229/blogs/blob/master/BestPractices/bilibili/Banner.md

  • 在线笔记

  • 最近花了点时间把笔记整理到语雀上了,方便同学们阅读:公众号回复笔记或者简历

  • 9143d20344e837c3aa6635d8acee55d3.png
  • 最后

  • 1.看到这里了就点个在看支持下吧,你的「点赞,在看」是我创作的动力。

  • 2.关注公众号前端壹栈,回复「1」加入前端交流群!「在这里有好多前端开发者,会讨论前端知识,互相学习」!

  • 3.也可添加公众号【前端壹栈】,一起成长27248e9667c1113fd70350248b9d87b7.png

转载自:https://github.com/a1029563229/blogs/blob/master/BestPractices/bilibili/Banner.md

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值