做一个摩天轮的效果

279 阅读3分钟

前言

前面一些文章我们介绍了 tailwinds变换和动画less(sass),这篇文章我们就利用他们实现一个旋转摩天轮效果(实际上主要使用的是 动画、sass,less 使用的没有 sass 高,也换成 sass 了,tailwinds 是基础,设置一些基础css不多介绍)

先看看效果(比较懒没放图片)

image.png

实现步骤和问题

下面介绍一下实现步骤 和 中间可能出现的问题以及解决方案,如果后面介绍代码有不理解的,可以参考下面

要实现摩天轮要经过如下步骤

  1. 创建一个父节点盒子,用于外部模仿摩天轮外圈旋转效果,通过父节点带动子节点旋转
  2. 子节点之间根据数量平均分割一圈,先使用绝对布局设置到与顶部中心对齐,然后通过循环,设置子节点 nth-child,实现平分弧度
  3. 由于重力效果,子节点应该自身保持垂直方向,盒子不应当旋转(否则里面的人没办法平稳坐着),因此需要处理自身随着父节点旋转问题,反向自转解决
  4. 添加两个动画,父节点顺时针,子节点元素顺时针

问题与解决方案:

  • 子节点通过循环设置 nth-child,那么也是默认相对自己中心,无法形成图片效果?
    • 可以通过设置 transfrom-origin 也就是旋转初始点,可以认为是锚点,改变其位置为父节点中心位置即可
  • 子节点已经设置 transfrom 了,在设置自身的 transfrom 动画,会影响实际效果吧?
    • 可以通过给添加孙子节点,让孙子节点反向自转即可,这样就互不影响了
  • 孙子节点动画发现有问题,即使反向旋转,也是有的节点有正常重力效果,有些没有?
    • 孙子节点默认为了水平已经反向自转了,也就是自带偏移了,执行动画时,可以添加上这个偏移即可,结束动画添加上偏移就行了(开始动画也可以添加,因为默认就有,所以也没啥必要哈)

实现

先编写 css ,一个父节点,几个子节点(item-view),每个子节点各有一个孙子节点(假的img,所以起名img😂)

<div id="circle_bkg" class="rounded-full border-[1px] border-red-500">
    <div class="item-view">
      <div class="img bg-amber-200" />
    </div>
    <div class="item-view">
      <div class="img bg-amber-700" />
    </div>
    <div class="item-view">
      <div class="img bg-green-400" />
    </div>
    <div class="item-view">
      <div class="img bg-blue-400" />
    </div>
    <div class="item-view">
      <div class="img bg-cyan-500" />
    </div>
</div>

接下来就是重头戏了,编写我们的css 了

//标记我们的父节点宽高、子节点个数(孙子节点个数),以及平均弧度
$parentSize: 400px;
$n: 5;
//有人不加 calc 发现也没事,我不加就报错了哈,可能是vue的使用问题,加上😂
$degPer: calc(360deg / 5);

//设置动画连续滚动
#circle_bkg {
  animation: circleFrame 10s linear infinite;
  width: $parentSize;
  height: $parentSize;
  position: relative;
}

//设置子布局为绝对布局,其相对于父节点的顶部中心,大小约 20%
.item-view {
  position: absolute;
  width: 20%;
  height: 20%;
  left: 40%;
  //向上偏移 10%
  top: -10%;
  
  //设置子节点变换,让其围绕外部一个点旋转变换,也就是父节点中心
  //默认应该是 50% 的父节点宽度,实际上我们为了保持中心在轴线,向上偏移了 10%,要加上
  //那么就是 0.6倍的父节点宽度了,x则是父节点中心直接设置center
  transform-origin: center $parentSize * 0.6;

  //循环处理节点情况
  @for $i from 1 through $n {
    //无引号字符串需要 #{} 方式插值
    &:nth-child(#{$i}) {
      $deg: $degPer * ($i - 1); //索引 * 弧度 = 当前节点弧度(索引从 1~n 开始所以要减1)
      transform: rotateZ($deg); //设置子节点根据弧度旋转
      
      //孙子节点
      .img {
        //由于设置了初始偏移 transform,所以用css变量记录一下,方便动画使用
        //sass变量不能在动画使用忽略,直接使用css变量即可
        --initialDeg: #{-$deg};
        //由于父节点旋转,孙子节点也旋转了,若想符合重力效果好,反向旋转同样角度即可
        transform: rotateZ(-$deg); //为了保证水平放置,里面的 img 需要反转同样角度
        animation: selfFrame 10s linear infinite;
      }
    }
  }
}

.img {
  width: 100%;
  height: 100%;
}

@keyframes circleFrame {
  to {
    transform: rotateZ(360deg);
  }
}

@keyframes selfFrame {
  to {
    //设置偏移是,需要加上默认的偏移,这样就可以实现效果了
    //需要注意是孙子节点是反向旋转,所以是 -360deg
    transform: rotateZ(calc(-360deg + var(--initialDeg)));
  }
}

最后

css 基础知识有了,有时候做动画真的需要一些思路,需要一些想象力,不然空有知识无用武之地了,当然如果想象力还是不足够,那么可以学习,毕竟学习使人进步,不是每个人都是天才!

学习使人进步,俺也一样!🤣