炫酷的图片破碎效果

365 阅读2分钟

炫酷的图片破碎效果

animation的使用

animation-direction的四个值
1.normal:默认值,不进行反方向播放;
2.reverse:全部播放都是用反方向播放;
3.alternate:在奇数次数(1、3、5)的时候正向播放,偶数次数(2、4、6)进行反向播放;
4.alternate-reverse:在偶数次数(1、3、5)的时候正向播放,奇数次数(2、4、6)进行反向播放;

animation-timing-function属性(时间曲线)

`animation-timing-function`属性是为动画制定从开始到结束时的播放速度曲线,比如由快到慢,或者由慢到快等;
  • animation-timing-function的几个值
    1.linear:表示动画一直以匀速进行播放;贝赛尔函数cubic-bezier(0,0,0.25,1)
    2.ease:默认值,表示动画先慢后快,在即将结束时再变慢;cubic-bezier(0.25,0.1,0.25,1)
    3.ease-in:动画由慢到快直至结束;cubic-bezier(0.42,0,1,1)
    4.ease-out:动画由快到慢直至结束;cubic-bezier(0,0,0.58,1)
    5.ease-in-out:动画由慢到快再到慢直至结束,与ease不同的是它均等得分为三份,而ease是只在结束时变慢;cubic-bezier(0.42,0,0.58,1)
    6.标注时间:也可以直接标注一个时间(以s做单位)来规定动画全称以该速度进行播放;
    7.贝赛尔函数:也可以使用贝赛尔函数来对动画的播放时间曲线进行规定;

home页面来设置图片要破碎的个数 代码附上:

<template>
  <div class="home">
    <div style="margin: 10px">图片破碎效果动画</div>
    平方
    <input v-model="square" type="text" />
    <n-component :square="square" />
  </div>
</template>

<script>
import NComponent from "./component.vue";

export default {
  name: "Home",
  components: {
    NComponent,
  },
  data() {
    return {
      square: "10",
    };
  },
};
</script>

component组件文件来实现图片破碎的具体动画效果

原理:

1.先将图片分成一个个小图片

2.点击‘破碎效果’按钮,给每个小图片添加动画效果

3.animationStyle 动画方法,通过四个象限来区别图片运动轨迹

代码附上:

<template>
  <div class="page">
    <button class="btn" @click="onClick">破碎效果</button>
    <div class="container" :style="fragmentStyle">
      <div class="fragment">
        <div v-for="(item, i) in Number(square)" :key="i">
          <div
            v-for="(item1, j) in Number(square)"
            :key="j"
            :class="[{ child: animationStatus }]"
            :style="[
              childStyle(),
              {
                'background-position': `-${i * squareWidth}px -${j * squareHeight}px`,
              },
              { transform: animationStatus ? animationStyle(i, j) : 'none' },
              { opacity: animationStatus ? '0' : '1' },
            ]"
          />
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import testImg from "./test.jpg";
export default {
  data() {
    return {
      testImg,
      imgWidth: null,
      imgHeight: null,
      squareWidth: null,
      squareHeight: null,
      animationStatus: false,
    };
  },
  props: {
    square: String,
  },
  computed: {
    squareHalf() {
      return Number(this.square) / 2;
    },
    fragmentStyle() {
      return {
        width: this.imgWidth + "px",
        minWidth: this.imgWidth + "px",
        height: this.imgHeight + "px",
      };
    },
  },
  methods: {
    getImgInfo() {
      let img = new Image();
      img.src = this.testImg;
      img.onload = () => {
        this.imgWidth = img.width;
        this.imgHeight = img.height;
        this.squareWidth = Math.floor(img.width / Number(this.square));
        this.squareHeight = Math.floor(img.height / Number(this.square));
      };
    },
    onClick() {
      this.animationStatus = true;
    },
    childStyle() {
      return {
        backgroundImage: `url(${testImg})`,
        backgroundRepeat: "no-repeat",
        width: this.squareWidth + "px",
        height: this.squareHeight + "px",
        border: "1px solid greenyellow",
      };
    },
    animationStyle(i, j) {
      let size = 700;
      let quadrantOneAndThree =
        (i < this.squareHalf && j < this.squareHalf) || (i >= this.squareHalf && j < this.squareHalf);
      let quadrantOneAndTwo =
        (i < this.squareHalf && j < this.squareHalf) || (i < this.squareHalf && j >= this.squareHalf);
      let directionX = quadrantOneAndThree ? "+" : "-";
      let directionY = quadrantOneAndTwo ? "-" : "+";
      return `perspective(100px) translate3d(${
        directionX + Math.floor(Math.random() * ((i + 1) * size + (j * 2 + 1) * 3))
      }px, ${
        directionY + Math.floor(Math.random() * ((i + 1) * size + (j * 4 + 1) * 2))
      }px, 50px)  rotateY(${Math.floor(Math.random() * (i * j + 20))}deg) rotateX(${Math.floor(
        Math.random() > 0.6 ? -i * Math.random() * size : j * Math.random() * size,
      )}deg)`;
    },
  },
  watch: {
    square(val) {
      this.getImgInfo();
    },
  },
  created() {
    this.getImgInfo();
  },
};
</script>

<style scoped lang="scss">
div,
html,
body {
  margin: 0px;
  padding: 0px;
}
.btn {
  margin: 10px;
  background: skyblue;
  color: #fff;
  padding: 8px 20px;
  border: 1px solid skyblue;
  border-radius: 4px;
}

.container {
  position: fixed;
  top: 50%;
  left: 50%;
  width: 50%;
  min-width: 320px;
  height: auto;
  z-index: 2000;
  -webkit-transform: translateX(-50%) translateY(-50%);
  -moz-transform: translateX(-50%) translateY(-50%);
  -ms-transform: translateX(-50%) translateY(-50%);
  transform: translateX(-50%) translateY(-50%);
  .fragment {
    display: flex;
    flex-wrap: wrap;
  }
  .child {
    transition-property: transform, opacity;
    transition-duration: 1s;
    transition-delay: 0s;
    transition-timing-function: ease-out;
  }
}
</style>

附上效果图

企业微信截图_1665386937466.png

企业微信截图_16653869685503.png