手把手教你使用Vue3实现图片散落效果
基于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>
本文网址:https://www.zztuku.com/detail-11766.html
站长图库 - 手把手教你使用Vue3实现图片散落效果
申明:本文转载于《掘金社区》,如有侵犯,请 联系我们 删除。
您还没有登录,请 登录 后发表评论!
提示:请勿发布广告垃圾评论,否则封号处理!!