vue+h5实现弧形科技感可触控轮播

10 篇文章 0 订阅
3 篇文章 0 订阅

场景:实现一个多个星球切换的交互效果,要有科技感。因此做了一个弧形的可触控星球切换效果。一屏展示三个星球,旁边两个星球加了蒙版,中间的为目标星球,加了放大效果使之更加突出。

实现效果:

星球触控转动

思路:

  1. 布局是一个进行圆周运动的容器,容器内固定展示有 6 个星球,一半隐藏,一半展示
  2. 根据 touch 事件,获取判断触控的位置,让容器正向或逆向转动
  3. 写了一个负数索引的方法,通过 ref 获取到对应节点,每次转动都会给当前星球添加对应位置的 class 名,进行特殊样式展示

代码:

<template>
    <div class="kp-wrap">
        <div id="box" ref="box" style="transform:rotate(0deg)" @touchstart="boxTouchStart" @touchmove="boxTouchMove" @touchend="boxTouchEnd">
            <div class="out-circle">
                <div v-for="(item, index) in newStarList" :key="index" class="star-item">
                    <p :ref="'itemImg'+index" class="star-info">
                        <img :src="item.imgUrl" alt="">
                    </p>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
export default {
  name: 'StarDemo',
  data () {
    return {
      deg: 0,
      startX: 0,
      endX: 0,
      startList: [],
      newStarList: [],
      anIdxList: ['1', '2', '3', '4', '5', '6'],
      anIdx: 0
    }
  },
  created () {
    this.initData()
  },
  mounted () {
    this.$refs.itemImg1[0].classList.add('star-2')
  },
  methods: {
    initData () {
      this.startList = [{
        imgUrl: require('../assets/images/01.png')
      },
      {
        imgUrl: require('../assets/images/02.png')
      },
      {
        imgUrl: require('../assets/images/03.png')
      },
      {
        imgUrl: require('../assets/images/04.png')
      },
      {
        imgUrl: require('../assets/images/05.png')
      },
      {
        imgUrl: require('../assets/images/06.png')
      }
      ]
      this.newStarList = JSON.parse(JSON.stringify(this.startList))
    },
    boxTouchStart (e) {
      this.pointShow = false
      if (this.startList.length > 3) {
        const touch = e.touches[0] // 获取触摸对象
        this.startX = touch.clientX // 获取触摸坐标
        this.endX = 0
        console.log(touch)
      }
    },
    boxTouchMove (e) {
      if (this.startList.length > 3) {
        this.endX = e.touches[0].clientX // 获取触摸坐标
      }
    },
    boxTouchEnd (e) {
      if (this.startList.length > 3 && this.endX) {
        this.deg = parseInt(this.$refs.box.style.transform.replace('rotate(', ''))
        // 向右边滑动
        if (this.endX - this.startX > 0) {
          if (this.deg === 0) {
            console.log('已经到第一个了')
          } else {
            this.anIdx++
            this.deg = this.deg + 60
            console.log(this.deg)

            this.$refs.box.style.transform = 'rotate(' + this.deg + 'deg)'
            this.newStarList.forEach((item, index) => {
              this.$refs[`itemImg${index}`][0].className = `star-${this.createArray(this.anIdxList)[index + this.anIdx]}`
            })
          }
        } else {
          if (Math.abs(this.anIdx) === this.startList.length - 2) {
            console.log('已经到最后一个了')
          } else {
            this.anIdx--
            this.deg = this.deg - 60
            console.log(this.deg)

            this.$refs.box.style.transform = 'rotate(' + this.deg + 'deg)'
            this.newStarList.forEach((item, index) => {
              // debugger
              this.$refs[`itemImg${index}`][0].className = `star-${this.createArray(this.anIdxList)[index - Math.abs(this.anIdx)]}`
            })
          }
        }
      }
    },
    createArray (arr) {
      const length = arr.length
      return new Proxy(arr, {
        get (target, key) {
          key = +key
          while (key < 0) {
            key += length
          }
          return target[key]
        }
      })
    }
  }
}
</script>

<style lang="scss" scoped>
.kp-wrap {
  position: relative;
  width: 100%;
  height: 100vh;
  top: 0;
  left: 0;
  background: #040c27;
  background-size: 100%;
  overflow: hidden;
  #box{
    position: relative;
    top: 30%;
    left: -3rem;
    height:6rem;
    width:6rem;
    text-align:Center;
    color:#fff;
    font-size: .2rem;
    transition: all 1s;
    border-radius:50%;
  }
  #box .out-circle{
    position: absolute;
    top: 50%;
    left: 50%;
    margin-left: -1rem;
    margin-top: -1rem;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    display: inline-block;
  }
  #box .star-item{
    position: absolute;
    left: 50%;
    top: 50%;
    margin-left: -2rem;
    margin-top: -2rem;
    width: 4rem;
    height: 4rem;
    border-radius: 50%;
  }
  #box .star-item .star-info {
    display: flex;
    flex-direction: column;
  }
  #box .out-circle div:nth-of-type(1){transform: rotate(120deg);}
  #box .out-circle div:nth-of-type(2){transform: rotate(180deg);}
  #box .out-circle div:nth-of-type(3){transform: rotate(240deg);}
  #box .out-circle div:nth-of-type(4){transform: rotate(300deg);}
  #box .out-circle div:nth-of-type(5){transform: rotate(0deg);}
  #box .out-circle div:nth-of-type(6){transform: rotate(60deg);}

  #box .out-circle div p {
    height:3rem;
    width:3rem;
    border-radius:50%;
    img {
      display:block;
      height:100%;
      width:100%;
      border-radius: 50%;
      box-shadow: 0 0 0.5rem 0rem #2a9bf4;
    }
    &:before {
      content: '';
      display: block;
      width: 0.01rem;
      height: 0.01rem;
      position: absolute;
      left: 50%;
      top: 50%;
      box-shadow: 0 0 2rem 1.5rem #040c27;
      z-index: 999;
      color: #333848;
    }
  }
  //#box .out-circle div p {transform: translateX(-4rem)}
  #box .out-circle div:nth-of-type(1) p{ transform: translateX(-4rem) rotate(-120deg); }
  #box .out-circle div:nth-of-type(2) p{ transform: translateX(-4rem) rotate(-180deg); }
  #box .out-circle div:nth-of-type(3) p{ transform: translateX(-4rem) rotate(-240deg); }
  #box .out-circle div:nth-of-type(4) p{ transform: translateX(-4rem) rotate(-300deg); }
  #box .out-circle div:nth-of-type(5) p{ transform: translateX(-4rem) rotate(0deg); }
  #box .out-circle div:nth-of-type(6) p{ transform: translateX(-4rem) rotate(-60deg);}

}

@keyframes an-point {
  0% {
    left: 3rem;
    top: 3rem;
  }
  100% {
    left: 5rem;
    top: 7rem;
  }
}
@keyframes an-1 {
  0% {
    transform: translateX(-4rem) scale(1) rotate(-120deg);
  }
  100% {
    transform: translateX(-4rem) scale(1) rotate(-120deg);
  }
}
@keyframes an-2 {
  0% {
    transform: translateX(-4rem) rotate(-180deg) scale(1);
  }
  100% {
    transform: translateX(-4rem) rotate(-180deg) scale(1.3);
  }
}
@keyframes an-3 {
  0% {
    transform: translateX(-4rem) scale(1) rotate(-240deg);
  }
  100% {
    transform: translateX(-4rem) scale(1) rotate(-240deg);
  }
}
@keyframes an-4 {
  0% {
    transform:  translateX(-4rem) scale(1) rotate(-300deg);
  }
  100% {
    transform:  translateX(-4rem) scale(1) rotate(-300deg);
  }
}

@keyframes an-5 {
  0% {
    transform:  translateX(-4rem) scale(1) rotate(0);
  }
  100% {
    transform:  translateX(-4rem) scale(1) rotate(0);
  }
}

@keyframes an-6 {
  0% {
    transform: translateX(-4rem) scale(1) rotate(-120deg);
  }
  100% {
    transform: translateX(-4rem) scale(1) rotate(-120deg);
  }
}
.star-1 { animation: an-1 2s forwards; }
.star-2 {
  animation: an-2 2s forwards;
  &:before {
    content: '';
    box-shadow: none !important;
  }
}
.star-3 { animation: an-3 2s forwards; }
.star-4 { animation: an-4 2s forwards; }
.star-5 { animation: an-5 2s forwards; }
.star-6 { animation: an-6 2s forwards; }

</style>

github地址

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值