Home  >  Article  >  Web Front-end  >  Teach you step by step how to use Vue3 to achieve the image scattering effect

Teach you step by step how to use Vue3 to achieve the image scattering effect

青灯夜游
青灯夜游forward
2022-04-27 10:57:192479browse

How to achieve image scattering effect based on Vue3? The following article will introduce to you how to use Vue3 to achieve the image scattering effect. I hope it will be helpful to you!

Teach you step by step how to use Vue3 to achieve the image scattering effect

Today is another wonderful day of fishing. I have just entered the workplace. I feel that everything is new and the tasks given by the instructor are not many (it would be great if it was like this every day) ), so I started to study with pay. (Learning video sharing: vuejs tutorial)

What to do

When I was wandering around on the Internet, I accidentally saw an animation The effect was good, so I decided to start making some. To put it simply, it was a complete picture. After a while, it suddenly broke apart. I thought it was very interesting, so I created a new folder.

Something went wrong

After an afternoon of fishing, the company was bustling with people, but I felt out of place (too idle). I don’t know how many people looked at me with questioning eyes. (doesn't this guy work), but I'm just immersed in my code. Finally managed to finish a less ugly version.

Teach you step by step how to use Vue3 to achieve the image scattering effect

Principle

To put it bluntly, the picture cracking effect is to create 100 divs, each div has its own background image. Use the backgroundPosition attribute to control the position of the background image of each div. Finally, put it together like a complete picture. Add animation effects to each div. Each div has a different rotation angle and different moving distance. Different orientations make the entire image spread out like glass.

HTML structure

Two divs are used here, #break is used as a container for 100 divs, #InBox is used to bind the background of the next one Picture

<div id="animateBox" v-show="showImg">
        <div id="break"></div>
        <div id="InBox"></div>
</div>

Prepare 5 pictures

import bgImg5 from &#39;../../assets/img/1/yTeach you step by step how to use Vue3 to achieve the image scattering effect&#39;
import bgImg4 from &#39;../../assets/img/1/yTeach you step by step how to use Vue3 to achieve the image scattering effect&#39;
import bgImg3 from &#39;../../assets/img/1/y3.png&#39;
import bgImg2 from &#39;../../assets/img/1/y4.png&#39;
import bgImg6 from &#39;../../assets/img/1/y5.png&#39;
import { ref, onMounted, onUnmounted } from &#39;vue&#39;
let index = 0
onMounted(() => {
  let imageSrcArr = [bgImg2, bgImg3, bgImg4, bgImg5, bgImg6]
  let imgloadPromiseArr: Array<Promise<HTMLImageElement>> = []
  let imageArr: Array<string> = []
  for (let i = 0; i < imageSrcArr.length; i++) {
    imgloadPromiseArr[i] = new Promise((resolve, reject) => {
      let img = new Image()
      img.src = imageSrcArr[i]
      img.onload = () => {
        resolve(img)
      }
    })
  }
  imgloadPromiseArr.forEach(item => {
    item.then(res => {
      imageArr.push(`url(${(<HTMLImageElement>res).currentSrc})`)
      index = imageArr.length
    })
  })
  })

Create div

Create 200 divs through createElement, and bind each div Set the length and width, add a background image to the div, use backgroundPosition to make the entire div look like a picture, and bind animation effects to the div.

for (let i = 0; i < 100; i++) {
      let div = document.createElement(&#39;div&#39;)
      let div1 = document.createElement(&#39;div&#39;)
      div.style.width = &#39;76px&#39;
      div.style.height = &#39;41px&#39; // 这里为什么是41px后面会提到
      div1.style.width = &#39;76px&#39;
      div1.style.height = &#39;40px&#39;
      div1.style.overflow = &#39;hidden&#39;
      div.style.boxSizing = &#39;border-box&#39;
      div.style.backgroundImage = imageArr[0]
      let positionX = -(i % 10) * 76 + &#39;px&#39;
      let positionY = -Math.floor(i / 10) * 40 + &#39;px&#39;
      div.style.backgroundPosition = positionX + &#39; &#39; + positionY
      div.style.backgroundSize = &#39;760px 400px&#39;
      let style = document.styleSheets[0]
      style.insertRule(`@keyframes secondrotate${i}
        {
            0%,30%{
                transform:scale(1)
            }
            70%
            {transform: rotateX(${180 + Math.random() * 720}deg) rotateY(${180 + Math.random() * 720}deg)}
            100%
            {transform: rotateX(${180 + Math.random() * 720}deg) rotateY(${180 + Math.random() * 720}deg)}
        }`)
      style.insertRule(`@keyframes secondrotateS${i}
        {
            0%,32%{
                transform:scale(1);opacity:1;
            }70%
            {transform: translateZ(${300 + Math.random() * 1500}px) translate(${(0.5 - Math.random()) * 500}px,${
        (0.5 - Math.random()) * 500
      }px);opacity:0}
            100%
            {transform: translateZ(${300 + Math.random() * 1500}px) translate(${(0.5 - Math.random()) * 500}px,${
        (0.5 - Math.random()) * 500
      }px);opacity:0}

        }`)
      div1.style.animation = `secondrotateS${i} 4.5s ease-out infinite`
      div.style.animation = `secondrotate${i} 4.5s ease-out infinite`
      div.style.transformOrigin = `center center`
      div1.appendChild(div)
      dom.appendChild(div1)
}

Switch background image

Use zIndex to determine which div is currently displayed

As mentioned before, InBox is the next one displayed After the breakBox is scattered, the zIndex of the breakBox is lowered to display the next picture. Then the breakBox with 100 divs completes the rendering of the next picture. The zIndex is increased and displayed.

 let count = 0
 let repeat = true
 let breakBox: HTMLDivElement = document.querySelector(&#39;#break&#39;)!
 let InBox: HTMLDivElement = document.querySelector(&#39;#InBox&#39;)!
  function changeImage(InBox: HTMLDivElement) {
    if (repeat) {
      breakBox.style.zIndex = &#39;-10&#39;
      count++
      count = count === index ? 0 : count
      repeat = false
      setTimeout(() => {
        repeat = true
        breakBox.style.zIndex = &#39;100&#39;
        let currentImageLength = count === index - 1 ? 0 : count + 1
        InBox.style.backgroundImage = imageArr[currentImageLength]
      }, 1000)
    }
  }

Every After the animation is completed, the above method will be adjusted. In order to display the next picture after the div fragments are broken, a timer is used to delay the method for 4 seconds because the div fragments completely disappear after 4 seconds. (When the animation is running at 70%, the transparency is 0)

const timer1 = ref<number>()
const timer2 = ref<number>()
for (let i = 0; i < 100; i++) {
      let div = document.createElement(&#39;div&#39;)
      let div1 = document.createElement(&#39;div&#39;)
      div.style.width = &#39;76px&#39;
      div.style.height = &#39;41px&#39;
      div1.style.width = &#39;76px&#39;
      div1.style.height = &#39;40px&#39;
      div1.style.overflow = &#39;hidden&#39;
      div.style.boxSizing = &#39;border-box&#39;
      div.style.backgroundImage = imageArr[0]
      let positionX = -(i % 10) * 76 + &#39;px&#39;
      let positionY = -Math.floor(i / 10) * 40 + &#39;px&#39;
      div.style.backgroundPosition = positionX + &#39; &#39; + positionY
      div.style.backgroundSize = &#39;760px 400px&#39;
      let style = document.styleSheets[0]
      style.insertRule(`@keyframes secondrotate${i}
        {
            0%,30%{
                transform:scale(1)
            }
            70%
            {transform: rotateX(${180 + Math.random() * 720}deg) rotateY(${180 + Math.random() * 720}deg)}
            100%
            {transform: rotateX(${180 + Math.random() * 720}deg) rotateY(${180 + Math.random() * 720}deg)}
        }`)
      style.insertRule(`@keyframes secondrotateS${i}
        {
            0%,32%{
                transform:scale(1);opacity:1;
            }70%
            {transform: translateZ(${300 + Math.random() * 1500}px) translate(${(0.5 - Math.random()) * 500}px,${
        (0.5 - Math.random()) * 500
      }px);opacity:0}
            100%
            {transform: translateZ(${300 + Math.random() * 1500}px) translate(${(0.5 - Math.random()) * 500}px,${
        (0.5 - Math.random()) * 500
      }px);opacity:0}

        }`)
      div1.style.animation = `secondrotateS${i} 4.5s ease-out infinite`
      div.style.animation = `secondrotate${i} 4.5s ease-out infinite`
      div.style.transformOrigin = `center center`
      div.addEventListener(&#39;animationstart&#39;, () => {
        timer1.value = setTimeout(() => {
          changeImage(InBox)
          div.style.backgroundImage = imageArr[count]
        }, 4000)
      })
      div.addEventListener(&#39;animationiteration&#39;, () => {
        timer2.value = setTimeout(() => {
          changeImage(InBox)
          div.style.backgroundImage = imageArr[count]
        }, 4000)
      })
      div1.appendChild(div)
      dom.appendChild(div1)
    }

There is a gap problem in divs

Teach you step by step how to use Vue3 to achieve the image scattering effect

In 100 divs Such a line will appear after the display. After many attempts, I found a way to increase the height of the div and set overflow:hidden on div1; the line disappears

Code details

<template>
  <div>
    <transition name="fadeIn">
      <div id="animateBox" v-show="showImg">
        <div id="break"></div>
        <div id="InBox"></div>
      </div>
    </transition>
  </div>
</template>

<script setup>
import bgImg5 from &#39;../../assets/img/1/yTeach you step by step how to use Vue3 to achieve the image scattering effect&#39;
import bgImg4 from &#39;../../assets/img/1/yTeach you step by step how to use Vue3 to achieve the image scattering effect&#39;
import bgImg3 from &#39;../../assets/img/1/y3.png&#39;
import bgImg2 from &#39;../../assets/img/1/y4.png&#39;
import bgImg6 from &#39;../../assets/img/1/y5.png&#39;
import { ref, onMounted, onUnmounted } from &#39;vue&#39;
const timer1 = ref<number>()
const timer2 = ref<number>()
const showImg = ref<boolean>(false)

onMounted(() => {
  let imageSrcArr = [bgImg2, bgImg3, bgImg4, bgImg5, bgImg6]
  let imgloadPromiseArr: Array<Promise<HTMLImageElement>> = []
  let imageArr: Array<string> = []
  for (let i = 0; i < imageSrcArr.length; i++) {
    imgloadPromiseArr[i] = new Promise((resolve, reject) => {
      let img = new Image()
      img.src = imageSrcArr[i]
      img.onload = () => {
        resolve(img)
      }
    })
  }
  imgloadPromiseArr.forEach(item => {
    item.then(res => {
      imageArr.push(`url(${(<HTMLImageElement>res).currentSrc})`)
      index = imageArr.length
    })
  })
  showImg.value = true
  let repeat = true
  function changeImage(InBox: HTMLDivElement) {
    if (repeat) {
      breakBox.style.zIndex = &#39;-10&#39;
      count++
      count = count === index ? 0 : count
      repeat = false
      setTimeout(() => {
        repeat = true
        breakBox.style.zIndex = &#39;100&#39;
        let currentImageLength = count === index - 1 ? 0 : count + 1
        InBox.style.backgroundImage = imageArr[currentImageLength]
      }, 1000)
    }
  }
  let count = 0
  let index = 0
  let breakBox: HTMLDivElement = document.querySelector(&#39;#break&#39;)!
  let InBox: HTMLDivElement = document.querySelector(&#39;#InBox&#39;)!
  InBox.style.backgroundImage = imageArr[1]
  const appendDom = (dom: HTMLElement) => {
    for (let i = 0; i < 100; i++) {
      let div = document.createElement(&#39;div&#39;)
      let div1 = document.createElement(&#39;div&#39;)
      div.style.width = &#39;76px&#39;
      div.style.height = &#39;41px&#39;
      div1.style.width = &#39;76px&#39;
      div1.style.height = &#39;40px&#39;
      div1.style.overflow = &#39;hidden&#39;
      div.style.boxSizing = &#39;border-box&#39;
      div.style.backgroundImage = imageArr[0]
      let positionX = -(i % 10) * 76 + &#39;px&#39;
      let positionY = -Math.floor(i / 10) * 40 + &#39;px&#39;
      div.style.backgroundPosition = positionX + &#39; &#39; + positionY
      div.style.backgroundSize = &#39;760px 400px&#39;
      let style = document.styleSheets[0]
      style.insertRule(`@keyframes secondrotate${i}
        {
            0%,30%{
                transform:scale(1)
            }
            70%
            {transform: rotateX(${180 + Math.random() * 720}deg) rotateY(${180 + Math.random() * 720}deg)}
            100%
            {transform: rotateX(${180 + Math.random() * 720}deg) rotateY(${180 + Math.random() * 720}deg)}
        }`)
      style.insertRule(`@keyframes secondrotateS${i}
        {
            0%,32%{
                transform:scale(1);opacity:1;
            }70%
            {transform: translateZ(${300 + Math.random() * 1500}px) translate(${(0.5 - Math.random()) * 500}px,${
        (0.5 - Math.random()) * 500
      }px);opacity:0}
            100%
            {transform: translateZ(${300 + Math.random() * 1500}px) translate(${(0.5 - Math.random()) * 500}px,${
        (0.5 - Math.random()) * 500
      }px);opacity:0}

        }`)
      div1.style.animation = `secondrotateS${i} 4.5s ease-out infinite`
      div.style.animation = `secondrotate${i} 4.5s ease-out infinite`
      div.style.transformOrigin = `center center`
      div.addEventListener(&#39;animationstart&#39;, () => {
        timer1.value = setTimeout(() => {
          changeImage(InBox)
          div.style.backgroundImage = imageArr[count]
        }, 4000)
      })
      div.addEventListener(&#39;animationiteration&#39;, () => {
        timer2.value = setTimeout(() => {
          changeImage(InBox)
          div.style.backgroundImage = imageArr[count]
        }, 4000)
      })
      div1.appendChild(div)
      dom.appendChild(div1)
    }
  }
  appendDom(breakBox)
})
onUnmounted(() => {
  typeof timer1 === &#39;number&#39; && clearTimeout(timer1)
  typeof timer2 === &#39;number&#39; && clearTimeout(timer2)
})
</script>

<style scoped>
@import url(&#39;../../css/comment/animate.css&#39;);
#animateBox {
  width: 100vw;
  height: calc(100vh - 50px);
  //  background-color: rgba(255, 255, 255, 0.6);
  #break {
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    margin: auto;
    width: 760px;
    height: 400px;
    display: flex;
    perspective: 1000px;
    transform-style: preserve-3d;
    flex-wrap: wrap;
    z-index: 100;
  }
  #InBox {
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    margin: auto;
    width: 760px;
    height: 400px;
    display: flex;
    perspective: 1000px;
    transform-style: preserve-3d;
    flex-wrap: wrap;
    z-index: 10;
    background-size: 760px 400px;
  }
}
</style>

(Learning video sharing: web front-end development, Introduction to programming)

The above is the detailed content of Teach you step by step how to use Vue3 to achieve the image scattering effect. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:juejin.cn. If there is any infringement, please contact admin@php.cn delete