标签沿轨道运动效果设计思路

·  阅读 1316
标签沿轨道运动效果设计思路

在开发移动端官网时,设计师想要实现标签沿轨道运动的效果(如下),点击标签时沿轨道运动,点击的标签到位置1,其他依次排列,并伴随轮播,每个位置的标签样式不同。

轨道运动.gif

设计思路如下:

一、标签动还是轨道动?

  • 标签动:不同类名设置宽高、定位属性,点击时改变标签赋值的类名;要分清标签的顺序和位置的顺序

image.png 此时标签位置顺序为[0,1,2,3,4,5]

当标签运动时 image.png 此时标签位置顺序为[5,0,1,2,3,4](标签0在位置5)

即:我们需要拿到当前点击标签的顺序值,这个标签到位置1,其他的依次排列 如,点击标签4,则标签顺序变为[2,3,4,5,0,1],点击标签5,顺序变为[1,2,3,4,5,0]

代码以vue+scss为例 HTML:

<ul class="label_ul">
          <li
            class="label_li"
            :class="`label${indexList[index]}`"
            :data-order="indexList[index]"
            ref="labelLi"
            @click="handleLabelChange($event, index)"
            v-for="(item, index) in labelList"
            :key="index"
          >
            <div>{{ item.name }}</div>
          </li>
        </ul>
复制代码

在data中存储当前的位置信息,indexList存储位置数组,初始为[0,1,2,3,4,5],之后点击动作即改变位置数组

CSS:

.label_ul {
        .label_li {
          position: absolute;
          transition: all 300ms ease-in-out 0s;
        }
        .label0 {
          width: 108px;
          height: 56px;
          top: 128px;
          left: calc(50% - 53px);
          z-index: 5;
          font-size: 18px;
          box-shadow: 0px 2px 0px 0px #2d63fb inset;
        }
        .label1{···}
        .label2{···}
}
复制代码

js:

method:{
    handleLabelChange(e, index) {
      this.order = e.currentTarget.dataset.order;//获取当前标签位置
      this.currentIndex = index;//获取点击当前标签的index
    },
},
watch:{
    currentIndex(n){
        if (n == 0) {
          this.indexList = [0, 1, 2, 3, 4, 5];
        } else if (n == 1) {
          this.indexList = [5, 0, 1, 2, 3, 4];
        } else if (n == 2) {
          this.indexList = [4, 5, 0, 1, 2, 3];
        } else if (n == 3) {
          this.indexList = [3, 4, 5, 0, 1, 2];
        } else if (n == 4) {
          this.indexList = [2, 3, 4, 5, 0, 1];
        } else if (n == 5) {
          this.indexList = [1, 2, 3, 4, 5, 0];
        }//此处标签个数比较固定,直接判断,可归纳为indexList[n]=0;
    }
}
复制代码

优化1:如果点击2/4,会直接到达位置0,期望效果,先到位置1/5,再到0

image.png

解决办法:当判断为位置2时,移到位置1,即将indexList末位删除移到首位; 当判断为位置4时,移到位置5,即将indexList首位删除移到末位;

watch:{
    currentIndex(n){
        if (this.order == 2) {
          let num = this.indexList.pop();
          this.indexList.unshift(num);
        } else if (this.order == 4) {
          let num = this.indexList.shift();
          this.indexList.push(num);
        }
        if (n == 0) {
          this.indexList = [0, 1, 2, 3, 4, 5];
        } else if (n == 1) {
          this.indexList = [5, 0, 1, 2, 3, 4];
        } else if (n == 2) {
          this.indexList = [4, 5, 0, 1, 2, 3];
        } else if (n == 3) {
          this.indexList = [3, 4, 5, 0, 1, 2];
        } else if (n == 4) {
          this.indexList = [2, 3, 4, 5, 0, 1];
        } else if (n == 5) {
          this.indexList = [1, 2, 3, 4, 5, 0];
        }//此处标签个数比较固定,直接判断,可归纳为indexList[n]=0;
    }
}
复制代码

优化2:为了防止连续点击位置错乱,可加一个防抖函数;

  • 轨道动:一个标签与轨道为整体,标签沿轨道运动实际为轨道的旋转

1、布局轨道与标签

image.png

    <div class="track">
       <div class="label">
       </div>
    </div>
复制代码

2、将轨道旋转、压缩、变为椭圆

image.png

.track{
    width: 315px;
    height:315px;
    transform: scaleY(0.5) rotateZ(180deg);
    border-radius: 50%;
}
.label{
    width: 108px;
    height: 56px;
    position: absolute;
    top: -28px;
    left: calc(50% - 54px);
    box-shadow: 0px 2px 0px 0px #2d63fb inset;
    transform: rotateZ(-180deg) scaleY(2);//先旋转,角度和轨道相反,后变为二倍
}
复制代码

轨道transform中先scaleY(),后旋转,标签中为了不受影响要和轨道的相反

transform是有顺序的,因为CSS3D完全是由CSS2D演化而来的,并没有3D空间,所以就会按照顺序进行渲染,transform会造成整个坐标轴的转换,因此顺序十分重要。 可参考CSS3D原理

3、此时标签的旋转则为轨道整体的运动,只需要改变旋转角度即可

屏幕录制2021-10-12 14.36.29.gif 此时轨道和标签都要设置动画,但是顺序相反

4、重叠多个标签轨道,轨道border隐藏即可

二、与轮播联动

再点击标签的事件中,获取当前点击的标签索引值,再利用轮播事件滑动到相应模块,此处轮播使用的swiper,利用slideToLoop()滑动至当前页面。

swiper设置:

      swiperOption: {
        initialSlide :0,
        loop: true,
        centeredSlides: true,
        slidesPerView: "auto",
        spaceBetween: 12,
        speed:750,
        observer: true,
        observeParents: true,
      },
复制代码

热知识:如果想实现swiper中间大两边小,滑块之间有空隙,可使用如下方法

    .swiper-slide {
        transform: scale(0.8);
    }
    .swiper-slide-active,.swiper-slide-duplicate-active{ 
        transform: scale(1); 
    }
复制代码
分类:
前端
标签:
分类:
前端
标签: