AI编程社区 前端三件套配合豆包MarsCode 实现钉钉官网动画
cover

前端三件套配合豆包MarsCode 实现钉钉官网动画

作者:PBitW要写出钉钉官网动画,首先第一步就是分析钉钉官网动画是怎么实现的!滚动滚轮发现:到了动画这里,界面是不会继续滚动的,而是等待动画执行完成后,才继续滚动!我们要实现的第一点就是:如何固定动画区域!只有搞定这个问题,下一个问题才是如何实现动画!如何固定动画区域这是一个解析图:灰色部分是网页内容比较长,蓝色部分是动...

egzosn  ·  2024-11-07 15:34:01 发布

作者:PBitW

要写出钉钉官网动画,首先第一步就是分析钉钉官网动画是怎么实现的!

前端三件套配合豆包MarsCode 实现钉钉官网动画_ci

滚动滚轮发现:到了动画这里,界面是不会继续滚动的,而是等待动画执行完成后,才继续滚动!我们要实现的第一点就是:如何固定动画区域!只有搞定这个问题,下一个问题才是如何实现动画!

如何固定动画区域

前端三件套配合豆包MarsCode 实现钉钉官网动画_官网_02

这是一个解析图:灰色部分是网页内容比较长,蓝色部分是动画的执行区域,相对来说比较高(不然滚动条一滚动就被带走了),但是只有这两个是不行的,还需要红色这个粘性定位的内容,等内容滚动到红色区域时,会一直固定,等父元素(蓝色部分)滚动到最上面的时候,底部会将红色部分一起带走(保证了红色区域不管怎么滚动,有一段时间一直在可视区域内)!

不懂粘性定位可以异步: 重学前端 css 详解Position,sticky定位的坑你知道吗?(第二十四天)

创建项目

现在我们一步一步来,配合 豆包MarsCode 完成代码 !首先在vscode里准备好我们的前端三件套文件!

前端三件套配合豆包MarsCode 实现钉钉官网动画_官网_03

前端三件套配合豆包MarsCode 实现钉钉官网动画_ci_04

其中:body 是灰色部分,playground 是蓝色部分,红色部分是 animation_container,这里只是模仿钉钉这个动画,所以里面用的是小方格 list-item!

豆包MarsCode 设置样式

使用 豆包MarsCode 设置样式!

豆包MarsCode 优点1

简单注释, 豆包MarsCode 生成的代码还是挺好用的

前端三件套配合豆包MarsCode 实现钉钉官网动画_官网_05

前端三件套配合豆包MarsCode 实现钉钉官网动画_数据结构_06

豆包MarsCode 优点2

可以通过尝试换书写注释来生成正确的代码,但是比较难试!

通过菜鸟不断的尝试,豆包MarsCode 居然真的自己写出来了:

前端三件套配合豆包MarsCode 实现钉钉官网动画_官网_07

效果如下:

前端三件套配合豆包MarsCode 实现钉钉官网动画_官网_08

然后我们自己优化一下:

/* 通配符取消margin、padding */
* {
  margin: 0;
  padding: 0;
}
body {
  height: 4000px;
}
/* 设置header占满屏幕,背景白色,文字黑色100px */
.header {
  height: 100vh;
  width: 100%;
  background-color: #fff;
  color: #000;
  font-size: 100px;
  text-align: center;
  line-height: 100vh;
}

.playground {
  height: 2000px;
  width: 100%;
  background-color: #000;
}
/* 设置animation_container为粘性定位,并占满屏幕 */
.animation_container {
  position: sticky;
  top: 0;
  height: 100vh;
  width: 100%;
}

/* 设置list在animation_container的中间,list-item排列成2行7列,均匀分布 */
.list {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  grid-template-rows: repeat(2, 1fr);
  grid-gap: 50px;
}

/* 请设置list-item的宽高为100px,高宽比为1:1 */
.list-item {
  width: 100px;
  height: 100px;
  aspect-ratio: 1/1;
  border-radius: 5%;
}

/* list-item有14个,请均匀分布在list中,且2行7列,颜色各不相同 */
.list-item:nth-child(1) {
  background-color: #f00;
}
.list-item:nth-child(2) {
  background-color: #0f0;
}
.list-item:nth-child(3) {
  background-color: #00f;
}
.list-item:nth-child(4) {
  background-color: #ff0;
}
.list-item:nth-child(5) {
  background-color: #0ff;
}
.list-item:nth-child(6) {
  background-color: #f0f;
}
.list-item:nth-child(7) {
  background-color: #fff;
}
.list-item:nth-child(8) {
  background-color: #f00;
}
.list-item:nth-child(9) {
  background-color: #0f0;
}
.list-item:nth-child(10) {
  background-color: #00f;
}
.list-item:nth-child(11) {
  background-color: #ff0;
}
.list-item:nth-child(12) {
  background-color: #0ff;
}
.list-item:nth-child(13) {
  background-color: #f0f;
}
.list-item:nth-child(14) {
  background-color: #fff;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.

结果

前端三件套配合豆包MarsCode 实现钉钉官网动画_ci_09

到此元素结构和样式搞定了!

js实现动画

现在到了实现动画的阶段了,首先要知道css动画是什么?css就是数值随时间的变化,但是这里没有时间,细心的同学就会发现虽然和时间无关,但是和滚动条相关了,所以要抽象成这个图

前端三件套配合豆包MarsCode 实现钉钉官网动画_官网_10

值随滚动条变化的图,而不是时间了!

实现获取动画曲线的函数

现在就是要写一个动画曲线函数,给我一个x,算出一个y,为了知道曲线函数需要传入scrollStart、scrollEnd、valueStart、valueEnd,然后剩下的就交给豆包MarsCode了!

写函数,然后输入几个参数后,MarsCode 自己就帮助我们生成好了!

前端三件套配合豆包MarsCode 实现钉钉官网动画_官网_11

自己想要完善一下(写的时候,MarsCode 也可以直接帮你,实在是牛)

前端三件套配合豆包MarsCode 实现钉钉官网动画_ci_12

function createAnimation(scrollStart, scrollEnd, valueStart, valueEnd) {
  return function (x) {
    if (x < scrollStart) return valueStart;
    if (x > scrollEnd) return valueEnd;

    return (
      valueStart +
      ((valueEnd - valueStart) * (x - scrollStart)) / (scrollEnd - scrollStart)
    );
  };
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

为什么实现这个函数?

就是用于备用,直接传值进函数,获得一个根据滚动条和属性直接的关系函数( 豆包MarsCode 也直接帮你完成,但是暂时不需要)

前端三件套配合豆包MarsCode 实现钉钉官网动画_数据结构_13

这里解释一下

opacity 这个函数就是:滚动条从0 到 100,那么透明度就从 0 到 1的函数曲线!

当然这里的滚动值不是很对,这个就是后面我们按需求修改!

根据当前滚动位置,计算每一个元素不同的数值

既然是动态变化的值,那肯定是这样的数据结构

前端三件套配合豆包MarsCode 实现钉钉官网动画_数据结构_14

所以要建立映射关系,将对象给每一个 dom

// 为每一个元素映射一个动画
const animationMap = newMap();
const items = document.querySelectorAll(".list-item");
const playground = document.querySelector(".playground");
const list = document.querySelector(".list");
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

然后就是两件事:

  1. 更新 animationMap
  2. 更新 dom 的 style

所以写出这两个函数

// 更新动画隐射
function updateAnimationMap() {}

// 将map结构用于元素
function updateStyle() {}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
更新 dom 的 style

其中比较好写的就是 更新 dom 的 style

思路:获取整个界面的滚动距离,循环 Map 去获取上面的对象,再循环对象获取值并调用函数!

有了思路, 豆包MarsCode 会直接帮你写好(写两个for,自己就出来了)

// 将map结构用于元素
function updateStyle() {
  const scrollY = window.scrollY;
  for (const [element, animation] of animationMap) {
    for (const key in animation) {
      // 自己添加的注释
      // 调用每个dom对应的动画函数
      // 动画函数的参数是当前的scrollY
      element.style.setProperty(key, animation[key](scrollY));
    }
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.

写完之后就调用,豆包MarsCode 也会帮你完成

前端三件套配合豆包MarsCode 实现钉钉官网动画_官网_15

更新 animationMap

思路:循环dom节点,并设置Map

写一个for, 豆包MarsCode 直接就帮你写好了

前端三件套配合豆包MarsCode 实现钉钉官网动画_官网_16

只是这里没这么简单,设置的是那个数据结构的对象,所以我们只保留设置部分!

function getDomAnimation(dom) {}

// 更新动画隐射
function updateAnimationMap() {
  for (const item of items) {
    animationMap.set(item, getDomAnimation(dom));
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
getDomAnimation

返回的是一个对象

return {
  opacity,
  transform,
};
  • 1.
  • 2.
  • 3.
  • 4.

这里的 opacity,transform 又可以通过 createAnimation 来获取!然后发现 scrollStart,scrollEnd 所有的dom是一样的,所以直接当参数传入!

function getDomAnimation(scrollStart, scrollEnd, dom) {
  const opacity = createAnimation(scrollStart, scrollEnd, 0, 1);
  const transform = createAnimation(scrollStart, scrollEnd, 0, 100);
  return {
    opacity,
    transform,
  };
}

// 更新动画隐射
function updateAnimationMap() {
  for (const item of items) {
    animationMap.set(item, getDomAnimation(scrollStart, scrollEnd, item));
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

确定什么时候滚动、什么时候滚动结束

// 更新动画隐射
function updateAnimationMap() {
  const playgroundRect = playground.getBoundingClientRect();
  const scrollY = window.scrollY;
  const scrollStart = playgroundRect.top + scrollY;
  const scrollEnd = playgroundRect.bottom + scrollY - window.innerHeight;

  for (const item of items) {
    animationMap.set(item, getDomAnimation(scrollStart, scrollEnd, item));
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

这个时候透明度的变化已经完成!

剩下的就是transform的一些属性,也可以按照 opacity 一样,不同的是这个 transformx\transformy ,需要计算。

function getDomAnimation(scrollStart, scrollEnd, dom) {
  const opacity = createAnimation(scrollStart, scrollEnd, 0, 1);
  const scale = createAnimation(scrollStart, scrollEnd, 0.5, 1);
  const Xtransform = createAnimation(scrollStart, scrollEnd, ?, 0);
  const Ytransform = createAnimation(scrollStart, scrollEnd, ?, 0);
  const transform = (x) => {
    return `scale(${scale(x)}) translate(${Xtransform(x)}px, ${Ytransform(x)}px)`;
  };
  return {
    opacity,
    transform,
  };
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

都是从中间出来的,所以:

function getDomAnimation(scrollStart, scrollEnd, dom) {
  const opacity = createAnimation(scrollStart, scrollEnd, 0, 1);
  const scale = createAnimation(scrollStart, scrollEnd, 0.5, 1);
  const { clientWidth, clientHeight, offsetTop, offsetLeft } = dom;
  console.log(clientWidth, clientHeight, offsetTop, offsetLeft);
  const listRect = list.getBoundingClientRect();
  const Xtransform = createAnimation(
    scrollStart,
    scrollEnd,
    listRect.width / 2 - clientWidth / 2 - offsetLeft,
    0
  );
  const Ytransform = createAnimation(
    scrollStart,
    scrollEnd,
    listRect.height / 2 - clientHeight / 2 - offsetTop,
    0
  );
  const transform = (x) => {
    return `translate(${Xtransform(x)}px, ${Ytransform(x)}px) scale(${scale(
      x
    )}) `;
  };
  return {
    opacity,
    transform,
  };
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.

至此,效果基本实现,再就是动画需要延时,通过data-设置delay来实现

<div data-delay="0" class="list-item"></div>
<div data-delay="1" class="list-item"></div>
<div data-delay="2" class="list-item"></div>
<div data-delay="3" class="list-item"></div>
<div data-delay="2" class="list-item"></div>
<div data-delay="1" class="list-item"></div>
<div data-delay="0" class="list-item"></div>
<div data-delay="0" class="list-item"></div>
<div data-delay="1" class="list-item"></div>
<div data-delay="2" class="list-item"></div>
<div data-delay="3" class="list-item"></div>
<div data-delay="2" class="list-item"></div>
<div data-delay="1" class="list-item"></div>
<div data-delay="0" class="list-item"></div>
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
function getDomAnimation(scrollStart, scrollEnd, dom) {
  // 注意这个不要超过滚动距离,不然就会导致超过的动画瞬间完成
  scrollStart += dom.dataset.delay * 200;
  const opacity = createAnimation(scrollStart, scrollEnd, 0, 1);
  const scale = createAnimation(scrollStart, scrollEnd, 0.5, 1);
  const { clientWidth, clientHeight, offsetTop, offsetLeft } = dom;
  const listRect = list.getBoundingClientRect();
  const Xtransform = createAnimation(
    scrollStart,
    scrollEnd,
    listRect.width / 2 - clientWidth / 2 - offsetLeft,
    0
  );
  const Ytransform = createAnimation(
    scrollStart,
    scrollEnd,
    listRect.height / 2 - clientHeight / 2 - offsetTop,
    0
  );
  const transform = (x) => {
    return `translate(${Xtransform(x)}px, ${Ytransform(x)}px) scale(${scale(
      x
    )}) `;
  };
  return {
    opacity,
    transform,
  };
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.

到此,钉钉官网动画基本上主要内容完成了,剩下的都是些图标什么的,还是比较简单的!

体验完 豆包MarsCode ,感觉智能提示等都很不错,但是 AI 只是辅助,重要的还是自己的能力过关!

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐

  • 浏览量 780
  • 收藏 0
  • 0

所有评论(0)

查看更多评论 
已为社区贡献1条内容