美文网首页
[笔记] Vue 实现加入购物车效果 小球 抛物线

[笔记] Vue 实现加入购物车效果 小球 抛物线

作者: 天使爱打盹 | 来源:发表于2019-07-23 22:35 被阅读0次
<template>
  <div class="wrapper">
    <div class="list-wrapper">
      <div class="item">
        <div class="left">
          <img src="./caomei.jpg" alt="">
          <a class="text-wrapper" href="javascript:;">
            <span class="tit">【精选】巧克力草莓 约500g/份</span>
            <span class="desc">鲜嫩多汁,入口即化,果肉细腻,果皮较薄</span>
            <span class="sale">月售1024件;好评86%</span>
            <span class="price">¥39.8</span>
          </a>
        </div>
        <div class="right">
          <div class="add">
            <span :class="['opt',{active:count1>0}]" v-show="count1>0">-</span>
            <span class="num" v-show="count1>0">{{count1}}</span>
            <span class="opt active" @click="addCount(1,$event)">+</span>
          </div>
        </div>
      </div>
      <div class="item">
        <div class="left">
          <img src="./chougan.jpg" alt="">
          <a class="text-wrapper" href="javascript:;">
            <span class="tit">四川不知火丑柑 约500g/份</span>
            <span class="sale">月售1024件;好评72%</span>
            <span class="price">¥6.6</span>
          </a>
        </div>
        <div class="right">
          <div class="add">
            <span :class="['opt',{active:count2>0}]" v-show="count2>0">-</span>
            <span class="num" v-show="count2>0">{{count2}}</span>
            <span class="opt active" @click="addCount(2,$event)">+</span>
          </div>
        </div>
      </div>
      <div class="item">
        <div class="left">
          <img src="./boluo.jpg" alt="">
          <a class="text-wrapper" href="javascript:;">
            <span class="tit">【鲜切】菠萝 约250g/份</span>
            <span class="sale">月售1024件;好评95%</span>
            <span class="price">¥9.8</span>
          </a>
        </div>
        <div class="right">
          <div class="add">
            <span :class="['opt',{active:count3>0}]" v-show="count3>0">-</span>
            <span class="num" v-show="count3>0">{{count3}}</span>
            <span class="opt active" @click="addCount(3,$event)">+</span>
          </div>
        </div>
      </div>
      <div class="item">
        <div class="left">
          <img src="./yingtao.jpg" alt="">
          <a class="text-wrapper" href="javascript:;">
            <span class="tit">本地 樱桃 【精选】 约250g/盒</span>
            <span class="desc">本地樱桃刚上市,可能有稍微一丁点的酸味哦~</span>
            <span class="sale">月售1024件;好评86%</span>
            <span class="price">¥19.9</span>
          </a>
        </div>
        <div class="right">
          <div class="add">
            <span :class="['opt',{active:count4>0}]" v-show="count4>0">-</span>
            <span class="num" v-show="count4>0">{{count4}}</span>
            <span class="opt active" @click="addCount(4,$event)">+</span>
          </div>
        </div>
      </div>
    </div>
    <div class="footer">
      <div :class="['cart',{active:count>0}]">
        <img src="./cart.png" alt="">
        <span class="count" v-show="count>0">{{count}}</span>
      </div>
      <div :class="['check',{active:count>0}]">
        去结算
      </div>
    </div>
    <div class="ball-container">
      <div v-for="(ball, index) in balls" :key="index">
        <transition name="cast-ball" @before-enter="ballBeforeEnter" @enter="ballEnter" @after-enter="ballAfterEnter">
          <div class="horiz-ball" v-show="ball.show">
            <div class="ball"></div>
          </div>
        </transition>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      count1: 0,
      count2: 0,
      count3: 0,
      count4: 0,
      balls: [
        { show: false },
        { show: false },
        { show: false },
        { show: false },
        { show: false },
        { show: false },
        { show: false },
        { show: false },
        { show: false }
      ],
      castBalls: []
    }
  },
  computed: {
    count() {
      return this.count1 + this.count2 + this.count3 + this.count4
    }
  },
  methods: {
    addCount(type, ev) {
      this.castBall(type, ev.target)
    },
    castBall(type, el) {
      // 找到第一个show为false(可用)的小球,然后就跳出循环
      this.balls.some(ball => {
        if (!ball.show) {
          ball.show = true
          ball.el = el
          ball.type = type
          this.castBalls.push(ball)
          return true
        }
      })
    },
    ballBeforeEnter(el) {
      let len = this.balls.length
      for (let i = 0; i < len; i++) {
        let ball = this.balls[i]
        if (ball.show) {
          let rect = ball.el.getBoundingClientRect()


          // x的值为X轴 起始点和落落脚点的距离
          let x = rect.left - 340
          let y = rect.top - window.innerHeight + 40
          el.style.webkitTransform = `translate3d(${x}px,0,0)`
          el.style.transform = `translate3d(${x}px,0,0)`
          let child = el.children[0]
          child.style.transform = `translate3d(0,${y}px,0)`
          child.style.webkitTransform = `translate3d(0,${y}px,0)`
        }
      }
    },
    ballEnter(el, done) {
      el.timer = setTimeout(() => {
        el.style.webkitTransform = `translate3d(0,0,0)`
        el.style.transform = `translate3d(0,0,0)`
        let child = el.children[0]
        child.style.transform = `translate3d(0,0,0)`
        child.style.webkitTransform = `translate3d(0,0,0)`
        el.addEventListener('transitionEnd', done)
        el.addEventListener('webkitTransitionEnd', done)
      }, 30)
    },
    ballAfterEnter(el) {
      let ball = this.castBalls.shift()
      if (ball) {
        ball.show = false
        el.style.display = 'none'
        clearTimeout(el.timer)
        switch (ball.type) {
          case 1:
            this.count1 += 1
            break
          case 2:
            this.count2 += 1
            break
          case 3:
            this.count3 += 1
            break
          case 4:
            this.count4 += 1
            break
        }
      }
    }
  }
}
</script>
<style lang="stylus" scoped>
.wrapper
  height 100%
  .list-wrapper
    background-color #fff
    padding 0 5px 0 10px
    .item
      display flex
      border-bottom 1px solid #f4f4f4
      padding 14px 0
      .left
        display flex
        flex 1
      .text-wrapper
        display flex
        flex-direction column
        justify-content space-between
      .tit
        color #333
      .desc, .sale
        font-size 12px
        color #999
      .right
        flex 0 0 84px
        display flex
        align-items flex-end
        justify-content flex-end
        .add
          display flex
          align-items center
          background-color #fff
          position relative
          z-index 200
          span
            color #818181
          .opt, .num
            width 28px
            height 28px
            line-height 28px
            text-align center
            font-size 20px
            &.active
              color #47b34f
          .num
            font-size 16px
  .footer
    position fixed
    bottom 0
    width 100%
    display flex
    height 48px
    border 1px solid #d9d9d9
    justify-content space-between
    z-index 1000
    .cart
      flex 0 0 40px
      height 40px
      background-color #bebebe
      position relative
      display flex
      align-items center
      justify-content center
      margin 5px 10px
      border-radius 50%
      transition 0.4s cubic-bezier(0.17, 0.67, 0.59, 1.48)
      &.active
        background-color #47b34f
        flex 0 0 50px
        height 50px
        transform translateY(-12px)
      img
        width 25px
      .count
        position absolute
        width 16px
        height 16px
        line-height 16px
        text-align center
        top 0
        right 0
        border-radius 50%
        background-color #ff5d5c
        color #ffffff
        font-size 12px
    .text
      flex 1
      background-color #fff
      display flex
      align-items center
      color #999
      padding-left 10px
    .check
      flex 0 0 115px
      width 115px
      height 100%
      display flex
      align-items center
      justify-content center
      background-color #bebebe
      color #ffffff
      &.active
        background-color #47b34f
  .ball-container
    /* 这里是外层的盒子做水平运动 */
    .horiz-ball
      position fixed
      /* X轴小球落脚点 */
      left 50%
      bottom 20px
      z-index 100
      transition 0.4s all linear
      .ball
        width 20px
        height 20px
        border-radius 50%
        background #47b34f
        /* 小球本身做加速运动 通过贝塞尔来模拟 */
        transition 0.4s all cubic-bezier(0.49, -0.29, 0.75, 0.41)
</style>

参考

vue实现类似添加购物车抛物线效果(类似饿了么,京东到家)

相关文章

网友评论

      本文标题:[笔记] Vue 实现加入购物车效果 小球 抛物线

      本文链接:https://www.haomeiwen.com/subject/nguzlctx.html