怎么使用Vue3实现图片散落效果
本篇内容介绍了“怎么使用Vue3实现图片散落效果”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
出现问题
一下午的摸鱼时光,间公司熙熙攘攘,我在其中却格格不入(太闲了),不知多少人投来质疑的眼光(这家伙不工作吗),但我只沉浸在我的代码里。终于勉强完成了一个不怎么丑的版本。
原理
图片破裂效果说白了就是搞了100个div,每个div都有自己的背景图片,通过backgroundPosition属性来控制每个div的背景图片方位,最后拼在一起,就像一张完整的图片一样,给每个div都加上动画效果,每个div的旋转角度不同,移动距离不同,移动方位不同来让整个图片像玻璃一样散开来。
HTML结构
这里用到了两个div,#break是用作为100个div的容器,#InBox是用来绑定下一张的背景图片
<div id="animateBox" v-show="showImg"> <div id="break"></div> <div id="InBox"></div> </div>
准备5张图片
import bgImg5 from '../../assets/img/1/y1.png' import bgImg4 from '../../assets/img/1/y2.png' import bgImg3 from '../../assets/img/1/y3.png' import bgImg2 from '../../assets/img/1/y4.png' import bgImg6 from '../../assets/img/1/y5.png' import { ref, onMounted, onUnmounted } from 'vue' 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 }) }) })
创建div
通过createElement创建200个div,每个div绑定长宽,给div添加背景图片,使用backgroundPosition来让整个div变得像一张图片,给div绑定动画效果。
for (let i = 0; i < 100; i++) { let div = document.createElement('div') let div1 = document.createElement('div') div.style.width = '76px' div.style.height = '41px' // 这里为什么是41px后面会提到 div1.style.width = '76px' div1.style.height = '40px' div1.style.overflow = 'hidden' div.style.boxSizing = 'border-box' div.style.backgroundImage = imageArr[0] let positionX = -(i % 10) * 76 + 'px' let positionY = -Math.floor(i / 10) * 40 + 'px' div.style.backgroundPosition = positionX + ' ' + positionY div.style.backgroundSize = '760px 400px' 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) }
切换背景图片
通过zIndex来让当前展示的div是哪一个
前面说过,InBox是展示的下一张图片,在breakBox散落完成之后,让breakBox的zIndex降低,展示出下一张图片,随后带有100个div的breakBox完成下一张图片的渲染,zIndex提高,展示出来
let count = 0 let repeat = true let breakBox: HTMLDivElement = document.querySelector('#break')! let InBox: HTMLDivElement = document.querySelector('#InBox')! function changeImage(InBox: HTMLDivElement) { if (repeat) { breakBox.style.zIndex = '-10' count++ count = count === index ? 0 : count repeat = false setTimeout(() => { repeat = true breakBox.style.zIndex = '100' let currentImageLength = count === index - 1 ? 0 : count + 1 InBox.style.backgroundImage = imageArr[currentImageLength] }, 1000) } }
每次动画完成之后会去调上面这个方法,为了能在div碎片破碎完毕,展示下一张图片,使用定时器将该方法进行延迟处理 4s是因为div碎片在4s后完全消失。(动画在运行70%的时候,透明度为0)
const timer1 = ref<number>() const timer2 = ref<number>() for (let i = 0; i < 100; i++) { let div = document.createElement('div') let div1 = document.createElement('div') div.style.width = '76px' div.style.height = '41px' div1.style.width = '76px' div1.style.height = '40px' div1.style.overflow = 'hidden' div.style.boxSizing = 'border-box' div.style.backgroundImage = imageArr[0] let positionX = -(i % 10) * 76 + 'px' let positionY = -Math.floor(i / 10) * 40 + 'px' div.style.backgroundPosition = positionX + ' ' + positionY div.style.backgroundSize = '760px 400px' 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('animationstart', () => { timer1.value = setTimeout(() => { changeImage(InBox) div.style.backgroundImage = imageArr[count] }, 4000) }) div.addEventListener('animationiteration', () => { timer2.value = setTimeout(() => { changeImage(InBox) div.style.backgroundImage = imageArr[count] }, 4000) }) div1.appendChild(div) dom.appendChild(div1) }
div存在间隙的问题
在100个div展示之后会出现这样的线,在经过多次尝试之后,找到了方法,将div的高度变大,div1设置overflow:hidden; 线回消失
代码详情
<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 '../../assets/img/1/y1.png' import bgImg4 from '../../assets/img/1/y2.png' import bgImg3 from '../../assets/img/1/y3.png' import bgImg2 from '../../assets/img/1/y4.png' import bgImg6 from '../../assets/img/1/y5.png' import { ref, onMounted, onUnmounted } from 'vue' 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 = '-10' count++ count = count === index ? 0 : count repeat = false setTimeout(() => { repeat = true breakBox.style.zIndex = '100' 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('#break')! let InBox: HTMLDivElement = document.querySelector('#InBox')! InBox.style.backgroundImage = imageArr[1] const appendDom = (dom: HTMLElement) => { for (let i = 0; i < 100; i++) { let div = document.createElement('div') let div1 = document.createElement('div') div.style.width = '76px' div.style.height = '41px' div1.style.width = '76px' div1.style.height = '40px' div1.style.overflow = 'hidden' div.style.boxSizing = 'border-box' div.style.backgroundImage = imageArr[0] let positionX = -(i % 10) * 76 + 'px' let positionY = -Math.floor(i / 10) * 40 + 'px' div.style.backgroundPosition = positionX + ' ' + positionY div.style.backgroundSize = '760px 400px' 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('animationstart', () => { timer1.value = setTimeout(() => { changeImage(InBox) div.style.backgroundImage = imageArr[count] }, 4000) }) div.addEventListener('animationiteration', () => { timer2.value = setTimeout(() => { changeImage(InBox) div.style.backgroundImage = imageArr[count] }, 4000) }) div1.appendChild(div) dom.appendChild(div1) } } appendDom(breakBox) }) onUnmounted(() => { typeof timer1 === 'number' && clearTimeout(timer1) typeof timer2 === 'number' && clearTimeout(timer2) }) </script> <style scoped> @import url('../../css/comment/animate.css'); #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>
“怎么使用Vue3实现图片散落效果”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注蜗牛博客网站,小编将为大家输出更多高质量的实用文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:niceseo99@gmail.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。
评论