如何封装一个翻转组件

690 阅读1分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

TIP 👉 滚滚长江东逝水,浪花淘尽英雄。是非成败转头空,青山依旧在,几度夕阳红。罗贯中《三国演义·卷首词》

前言

在我们日常项目开发中,我们经常会做一些翻转功能,所以封装了这款功能组件。

翻转组件

属性

1. isBack
  • 是否显示反面
  • 值为布尔类型
  • 默认值:false
2. duration
  • 动画时长
  • 值为数值类型,单位:毫秒
  • 默认值:325
3. direction
  • 翻转方向
  • 值为‘x’或者‘y’
  • x:沿x轴方向翻转,y:沿y轴方向翻转
  • 默认值:‘y’

插槽

1. front
  • 正面内容插槽
2. back
  • 反面内容插槽

示例代码

<template>
  <div class="flip-demo">
    <div class="flip-wrap">
      <BaseFlip :isBack="true" :duration="350" direction="y">
        <img slot="front" src="./img/card-a.png" alt="">
        <img slot="back" src="./img/card-b.png" alt="">
      </BaseFlip>
    </div>
    <div class="flip-wrap">
      <BaseFlip :isBack="false" :duration="240" direction="x">
        <img slot="front" src="./img/card-a.png" alt="">
        <img slot="back" src="./img/card-b.png" alt="">
      </BaseFlip>
    </div>
  </div>
</template>
<script>
import BaseFlip from '@/components/base/flip/index.vue'
export default {
  name: 'FlipDemo',
  components: {
    BaseFlip
  }
}
</script>
<style lang="scss" scoped>
.flip-demo{
  .flip-wrap{
    position: relative;
    width: 254px;
    height: 440px;
    margin: 60px auto;
    img{
      width: 100%;
      height: 100%;
    }
  }
}
</style>

实现flip.vue

<!-- 翻转组件 -->
<template>
  <div class="card" @click="doSwitch">
    <div class="flip" :class="[frontStatus]" :style="durationStyle">
      <slot name="front"></slot>
    </div>
    <div class="flip" :class="[backStatus]" :style="durationStyle">
      <slot name="back"></slot>
    </div>
  </div>
</template>
<script>
export default {
  name: 'Flip',
  props: {
    // 是否反面
    isBack: {
      type: Boolean,
      default: false
    },
    // 动画时长,单位:毫秒
    duration: {
      type: Number,
      default: 325
    },
    // 方向, x:沿x轴方向翻转,y:沿y轴方向翻转
    direction: {
      type: String,
      default: 'y'
    }
  },
  data () {
    let data = {
      backFlag: this.isBack,
      frontStatus: '',
      backStatus: ''
    }

    if (this.isBack) {
      data.frontStatus = 'hidde'
    } else {
      data.backStatus = 'hidde'
    }
    return data
  },
  computed: {
    durationStyle () {
      return {
        animationDuration: `${this.duration}ms`
      }
    }
  },
  watch: {
    backFlag (flag) {
      if (flag) {
        this.frontStatus = 'out-' + this.direction
        setTimeout(() => {
          this.$set(this, 'backStatus', 'in-' + this.direction)
        }, this.duration)
      } else {
        this.backStatus = 'out-' + this.direction
        setTimeout(() => {
          this.$set(this, 'frontStatus', 'in-' + this.direction)
        }, this.duration)
      }
    }
  },
  methods: {
    doSwitch () {
      this.backFlag = !this.backFlag
      this.$emit('flip', this.backFlag)
    }
  }
}
</script>
<style lang="scss" scoped>
.card, .flip{
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
}
.flip{
  backface-visibility: hidden;
  transform: translateX(0);
}
.in-x {
  animation-name: flipintobottom;
  // animation-duration: 325ms;
  animation-timing-function: ease-out;
}
.out-x {
  transform: rotateX(-90deg) scale(.9);
  animation-name: flipouttotop;
  animation-timing-function: ease-in;
  // animation-duration: 325ms;
}
.in-y {
  animation-name: flipintoright;
  // animation-duration: 325ms;
  animation-timing-function: ease-out;
}
.out-y {
  transform: rotateY(-90deg) scale(.9);
  animation-name: flipouttoleft;
  animation-timing-function: ease-in;
  // animation-duration: 325ms;
}
@keyframes flipouttoleft {
  from { transform: rotateY(0); }
  to { transform: rotateY(-90deg) scale(.9); }
}
@keyframes flipintoright{
  from { transform: rotateY(90deg) scale(.9); }
  to { transform: rotateY(0); }
}
@keyframes flipouttotop {
  from { transform: rotateX(0); }
  to { transform: rotateX(-90deg) scale(.9); }
}
@keyframes flipintobottom{
  from { transform: rotateX(90deg) scale(.9); }
  to { transform: rotateX(0); }
}
.hidde{
  opacity: 0;
}
</style>

「欢迎在评论区讨论」

希望看完的朋友可以给个赞,鼓励一下