手把手教你使用Vue3实现图片散落效果

 2866

基于Vue3怎么实现图片散落效果?下面本篇文章给大家介绍一下使用Vue3实现图片散落效果的方法,希望对大家有所帮助!


手把手教你使用Vue3实现图片散落效果


今天又是美好的摸鱼一天,刚刚进入职场,觉得一切都很新鲜,导师给的任务也不多(要是每天都是这样就好了),于是开始带薪学习。


做啥好呢

没事在网上乱逛的时候,偶然间看到一个动画效果不错,就决定上手做一些,简单的说就是一个完整的图片,在一段时间之后回突然破裂开来,觉得很有意思,就新建了一个文件夹。


出现问题

一下午的摸鱼时光,间公司熙熙攘攘,我在其中却格格不入(太闲了),不知多少人投来质疑的眼光(这家伙不工作吗),但我只沉浸在我的代码里。终于勉强完成了一个不怎么丑的版本。


手把手教你使用Vue3实现图片散落效果


原理

图片破裂效果说白了就是搞了100个div,每个div都有自己的背景图片,通过backgroundPosition属性来控制每个div的背景图片方位,最后拼在一起,就像一张完整的图片一样,给每个div都加上动画效果,每个div的旋转角度不同,移动距离不同,移动方位不同来让整个图片像玻璃一样散开来。


HTML结构

这里用到了两个div,#break是用作为100个div的容器,#InBox是用来绑定下一张的背景图片

  1. <div id="animateBox" v-show="showImg">
  2.         <div id="break"></div>
  3.         <div id="InBox"></div>
  4. </div>

准备5张图片

  1. import bgImg5 from '../../assets/img/1/y1.png'
  2. import bgImg4 from '../../assets/img/1/y2.png'
  3. import bgImg3 from '../../assets/img/1/y3.png'
  4. import bgImg2 from '../../assets/img/1/y4.png'
  5. import bgImg6 from '../../assets/img/1/y5.png'
  6. import { ref, onMounted, onUnmounted } from 'vue'
  7. let index = 0
  8. onMounted(() => {
  9.   let imageSrcArr = [bgImg2, bgImg3, bgImg4, bgImg5, bgImg6]
  10.   let imgloadPromiseArr: Array<Promise<HTMLImageElement>> = []
  11.   let imageArr: Array<string> = []
  12.   for (let i = 0; i < imageSrcArr.length; i++) {
  13.     imgloadPromiseArr[i] = new Promise((resolve, reject) => {
  14.       let img = new Image()
  15.       img.src = imageSrcArr[i]
  16.       img.onload = () => {
  17.         resolve(img)
  18.       }
  19.     })
  20.   }
  21.   imgloadPromiseArr.forEach(item => {
  22.     item.then(res => {
  23.       imageArr.push(`url(${(<HTMLImageElement>res).currentSrc})`)
  24.       index = imageArr.length
  25.     })
  26.   })
  27. })


创建div

通过createElement创建200个div,每个div绑定长宽,给div添加背景图片,使用backgroundPosition来让整个div变得像一张图片,给div绑定动画效果。

  1. for (let i = 0; i < 100; i++) {
  2.       let div = document.createElement('div')
  3.       let div1 = document.createElement('div')
  4.       div.style.width = '76px'
  5.       div.style.height = '41px' // 这里为什么是41px后面会提到
  6.       div1.style.width = '76px'
  7.       div1.style.height = '40px'
  8.       div1.style.overflow = 'hidden'
  9.       div.style.boxSizing = 'border-box'
  10.       div.style.backgroundImage = imageArr[0]
  11.       let positionX = -(% 10) * 76 + 'px'
  12.       let positionY = -Math.floor(/ 10) * 40 + 'px'
  13.       div.style.backgroundPosition = positionX + ' ' + positionY
  14.       div.style.backgroundSize = '760px 400px'
  15.       let style = document.styleSheets[0]
  16.       style.insertRule(`@keyframes secondrotate${i}
  17.         {
  18.             0%,30%{
  19.                 transform:scale(1)
  20.             }
  21.             70%
  22.             {transform: rotateX(${180 + Math.random() * 720}deg) rotateY(${180 + Math.random() * 720}deg)}
  23.             100%
  24.             {transform: rotateX(${180 + Math.random() * 720}deg) rotateY(${180 + Math.random() * 720}deg)}
  25.         }`)
  26.       style.insertRule(`@keyframes secondrotateS${i}
  27.         {
  28.             0%,32%{
  29.                 transform:scale(1);opacity:1;
  30.             }70%
  31.             {transform: translateZ(${300 + Math.random() * 1500}px) translate(${(0.5 - Math.random()) * 500}px,${
  32.         (0.5 - Math.random()) * 500
  33.       }px);opacity:0}
  34.             100%
  35.             {transform: translateZ(${300 + Math.random() * 1500}px) translate(${(0.5 - Math.random()) * 500}px,${
  36.         (0.5 - Math.random()) * 500
  37.       }px);opacity:0}
  38.  
  39.         }`)
  40.       div1.style.animation = `secondrotateS${i} 4.5s ease-out infinite`
  41.       div.style.animation = `secondrotate${i} 4.5s ease-out infinite`
  42.       div.style.transformOrigin = `center center`
  43.       div1.appendChild(div)
  44.       dom.appendChild(div1)
  45. }


切换背景图片

通过zIndex来让当前展示的div是哪一个

前面说过,InBox是展示的下一张图片,在breakBox散落完成之后,让breakBox的zIndex降低,展示出下一张图片,随后带有100个div的breakBox完成下一张图片的渲染,zIndex提高,展示出来

  1. let count = 0
  2. let repeat = true
  3. let breakBox: HTMLDivElement = document.querySelector('#break')!
  4. let InBox: HTMLDivElement = document.querySelector('#InBox')!
  5. function changeImage(InBox: HTMLDivElement) {
  6.   if (repeat) {
  7.     breakBox.style.zIndex = '-10'
  8.     count++
  9.     count = count === index ? 0 : count
  10.     repeat = false
  11.     setTimeout(() => {
  12.       repeat = true
  13.       breakBox.style.zIndex = '100'
  14.       let currentImageLength = count === index - 1 ? 0 : count + 1
  15.       InBox.style.backgroundImage = imageArr[currentImageLength]
  16.     }, 1000)
  17.   }
  18. }

每次动画完成之后会去调上面这个方法,为了能在div碎片破碎完毕,展示下一张图片,使用定时器将该方法进行延迟处理 4s是因为div碎片在4s后完全消失。(动画在运行70%的时候,透明度为0)

  1. const timer1 = ref<number>()
  2. const timer2 = ref<number>()
  3. for (let i = 0; i < 100; i++) {
  4.   let div = document.createElement('div')
  5.   let div1 = document.createElement('div')
  6.   div.style.width = '76px'
  7.   div.style.height = '41px'
  8.   div1.style.width = '76px'
  9.   div1.style.height = '40px'
  10.   div1.style.overflow = 'hidden'
  11.   div.style.boxSizing = 'border-box'
  12.   div.style.backgroundImage = imageArr[0]
  13.   let positionX = -(% 10) * 76 + 'px'
  14.   let positionY = -Math.floor(/ 10) * 40 + 'px'
  15.   div.style.backgroundPosition = positionX + ' ' + positionY
  16.   div.style.backgroundSize = '760px 400px'
  17.   let style = document.styleSheets[0]
  18.   style.insertRule(`@keyframes secondrotate${i}
  19.     {
  20.         0%,30%{
  21.             transform:scale(1)
  22.         }
  23.         70%
  24.         {transform: rotateX(${180 + Math.random() * 720}deg) rotateY(${180 + Math.random() * 720}deg)}
  25.         100%
  26.         {transform: rotateX(${180 + Math.random() * 720}deg) rotateY(${180 + Math.random() * 720}deg)}
  27.     }`)
  28.   style.insertRule(`@keyframes secondrotateS${i}
  29.     {
  30.         0%,32%{
  31.             transform:scale(1);opacity:1;
  32.         }70%
  33.         {transform: translateZ(${300 + Math.random() * 1500}px) translate(${(0.5 - Math.random()) * 500}px,${
  34.     (0.5 - Math.random()) * 500
  35.   }px);opacity:0}
  36.         100%
  37.         {transform: translateZ(${300 + Math.random() * 1500}px) translate(${(0.5 - Math.random()) * 500}px,${
  38.     (0.5 - Math.random()) * 500
  39.   }px);opacity:0}
  40.     }`)
  41.   div1.style.animation = `secondrotateS${i} 4.5s ease-out infinite`
  42.   div.style.animation = `secondrotate${i} 4.5s ease-out infinite`
  43.   div.style.transformOrigin = `center center`
  44.   div.addEventListener('animationstart', () => {
  45.     timer1.value = setTimeout(() => {
  46.       changeImage(InBox)
  47.       div.style.backgroundImage = imageArr[count]
  48.     }, 4000)
  49.   })
  50.   div.addEventListener('animationiteration', () => {
  51.     timer2.value = setTimeout(() => {
  52.       changeImage(InBox)
  53.       div.style.backgroundImage = imageArr[count]
  54.     }, 4000)
  55.   })
  56.   div1.appendChild(div)
  57.   dom.appendChild(div1)
  58. }


div存在间隙的问题


手把手教你使用Vue3实现图片散落效果


在100个div展示之后会出现这样的线,在经过多次尝试之后,找到了方法,将div的高度变大,div1设置overflow:hidden; 线回消失


代码详情

  1. <template>
  2.   <div>
  3.     <transition name="fadeIn">
  4.       <div id="animateBox" v-show="showImg">
  5.         <div id="break"></div>
  6.         <div id="InBox"></div>
  7.       </div>
  8.     </transition>
  9.   </div>
  10. </template>
  11.  
  12. <script setup>
  13. import bgImg5 from '../../assets/img/1/y1.png'
  14. import bgImg4 from '../../assets/img/1/y2.png'
  15. import bgImg3 from '../../assets/img/1/y3.png'
  16. import bgImg2 from '../../assets/img/1/y4.png'
  17. import bgImg6 from '../../assets/img/1/y5.png'
  18. import { ref, onMounted, onUnmounted } from 'vue'
  19. const timer1 = ref<number>()
  20. const timer2 = ref<number>()
  21. const showImg = ref<boolean>(false)
  22.  
  23. onMounted(() => {
  24.   let imageSrcArr = [bgImg2, bgImg3, bgImg4, bgImg5, bgImg6]
  25.   let imgloadPromiseArr: Array<Promise<HTMLImageElement>> = []
  26.   let imageArr: Array<string> = []
  27.   for (let i = 0; i < imageSrcArr.length; i++) {
  28.     imgloadPromiseArr[i] = new Promise((resolve, reject) => {
  29.       let img = new Image()
  30.       img.src = imageSrcArr[i]
  31.       img.onload = () => {
  32.         resolve(img)
  33.       }
  34.     })
  35.   }
  36.   imgloadPromiseArr.forEach(item => {
  37.     item.then(res => {
  38.       imageArr.push(`url(${(<HTMLImageElement>res).currentSrc})`)
  39.       index = imageArr.length
  40.     })
  41.   })
  42.   showImg.value = true
  43.   let repeat = true
  44.   function changeImage(InBox: HTMLDivElement) {
  45.     if (repeat) {
  46.       breakBox.style.zIndex = '-10'
  47.       count++
  48.       count = count === index ? 0 : count
  49.       repeat = false
  50.       setTimeout(() => {
  51.         repeat = true
  52.         breakBox.style.zIndex = '100'
  53.         let currentImageLength = count === index - 1 ? 0 : count + 1
  54.         InBox.style.backgroundImage = imageArr[currentImageLength]
  55.       }, 1000)
  56.     }
  57.   }
  58.   let count = 0
  59.   let index = 0
  60.   let breakBox: HTMLDivElement = document.querySelector('#break')!
  61.   let InBox: HTMLDivElement = document.querySelector('#InBox')!
  62.   InBox.style.backgroundImage = imageArr[1]
  63.   const appendDom = (dom: HTMLElement) => {
  64.     for (let i = 0; i < 100; i++) {
  65.       let div = document.createElement('div')
  66.       let div1 = document.createElement('div')
  67.       div.style.width = '76px'
  68.       div.style.height = '41px'
  69.       div1.style.width = '76px'
  70.       div1.style.height = '40px'
  71.       div1.style.overflow = 'hidden'
  72.       div.style.boxSizing = 'border-box'
  73.       div.style.backgroundImage = imageArr[0]
  74.       let positionX = -(% 10) * 76 + 'px'
  75.       let positionY = -Math.floor(/ 10) * 40 + 'px'
  76.       div.style.backgroundPosition = positionX + ' ' + positionY
  77.       div.style.backgroundSize = '760px 400px'
  78.       let style = document.styleSheets[0]
  79.       style.insertRule(`@keyframes secondrotate${i}
  80.         {
  81.             0%,30%{
  82.                 transform:scale(1)
  83.             }
  84.             70%
  85.             {transform: rotateX(${180 + Math.random() * 720}deg) rotateY(${180 + Math.random() * 720}deg)}
  86.             100%
  87.             {transform: rotateX(${180 + Math.random() * 720}deg) rotateY(${180 + Math.random() * 720}deg)}
  88.         }`)
  89.       style.insertRule(`@keyframes secondrotateS${i}
  90.         {
  91.             0%,32%{
  92.                 transform:scale(1);opacity:1;
  93.             }70%
  94.             {transform: translateZ(${300 + Math.random() * 1500}px) translate(${(0.5 - Math.random()) * 500}px,${
  95.         (0.5 - Math.random()) * 500
  96.       }px);opacity:0}
  97.             100%
  98.             {transform: translateZ(${300 + Math.random() * 1500}px) translate(${(0.5 - Math.random()) * 500}px,${
  99.         (0.5 - Math.random()) * 500
  100.       }px);opacity:0}
  101.  
  102.         }`)
  103.       div1.style.animation = `secondrotateS${i} 4.5s ease-out infinite`
  104.       div.style.animation = `secondrotate${i} 4.5s ease-out infinite`
  105.       div.style.transformOrigin = `center center`
  106.       div.addEventListener('animationstart', () => {
  107.         timer1.value = setTimeout(() => {
  108.           changeImage(InBox)
  109.           div.style.backgroundImage = imageArr[count]
  110.         }, 4000)
  111.       })
  112.       div.addEventListener('animationiteration', () => {
  113.         timer2.value = setTimeout(() => {
  114.           changeImage(InBox)
  115.           div.style.backgroundImage = imageArr[count]
  116.         }, 4000)
  117.       })
  118.       div1.appendChild(div)
  119.       dom.appendChild(div1)
  120.     }
  121.   }
  122.   appendDom(breakBox)
  123. })
  124. onUnmounted(() => {
  125.   typeof timer1 === 'number' && clearTimeout(timer1)
  126.   typeof timer2 === 'number' && clearTimeout(timer2)
  127. })
  128. </script>
  129.  
  130. <style scoped>
  131. @import url('../../css/comment/animate.css');
  132. #animateBox {
  133.   width: 100vw;
  134.   height: calc(100vh - 50px);
  135.   //  background-color: rgba(255, 255, 255, 0.6);
  136.   #break {
  137.     position: absolute;
  138.     left: 0;
  139.     top: 0;
  140.     right: 0;
  141.     bottom: 0;
  142.     margin: auto;
  143.     width: 760px;
  144.     height: 400px;
  145.     display: flex;
  146.     perspective: 1000px;
  147.     transform-style: preserve-3d;
  148.     flex-wrap: wrap;
  149.     z-index: 100;
  150.   }
  151.   #InBox {
  152.     position: absolute;
  153.     left: 0;
  154.     top: 0;
  155.     right: 0;
  156.     bottom: 0;
  157.     margin: auto;
  158.     width: 760px;
  159.     height: 400px;
  160.     display: flex;
  161.     perspective: 1000px;
  162.     transform-style: preserve-3d;
  163.     flex-wrap: wrap;
  164.     z-index: 10;
  165.     background-size: 760px 400px;
  166.   }
  167. }
  168. </style>


TAG标签:
本文网址:https://www.zztuku.com/detail-11766.html
站长图库 - 手把手教你使用Vue3实现图片散落效果
申明:本文转载于《掘金社区》,如有侵犯,请 联系我们 删除。

评论(0)条

您还没有登录,请 登录 后发表评论!

提示:请勿发布广告垃圾评论,否则封号处理!!

    编辑推荐