Vue中使用create-keyframe-animation與動(dòng)畫(huà)鉤子完成復(fù)雜動(dòng)畫(huà)
本篇文章主要介紹了 Vue中使用create-keyframe-animation與動(dòng)畫(huà)鉤子完成復(fù)雜動(dòng)畫(huà),分享給大家
如何實(shí)現(xiàn)這個(gè)動(dòng)畫(huà)?
效果分析
點(diǎn)`start`的時(shí)候,我們把整個(gè)動(dòng)畫(huà)拆分為兩種效果(過(guò)渡和動(dòng)畫(huà))。
1. 中間cd消失,下方播放條顯示,這是屬于`過(guò)渡`
2. `過(guò)渡`開(kāi)始的同時(shí),cd同時(shí)移動(dòng)、放大、縮小到左下方播放條 ,這屬于`動(dòng)畫(huà)`
上面的效果是【過(guò)渡】加【動(dòng)畫(huà)】同時(shí)使用完成的
- 對(duì)于第一種【過(guò)渡】,我們用vue中transition標(biāo)簽,加設(shè)置v-enter、v-leave-to、v-enter-active、v-leave-enter即可完成
- 對(duì)于第二種【動(dòng)畫(huà)】,我們就要用keyframe來(lái)完成了。
這里我們先完成第一種過(guò)渡
vue中模板節(jié)點(diǎn)
<template> <div class="index"> <transition> <div class="cd-box" ref="cdWrapper" v-show="fullScreen"> // CD圖片 (動(dòng)畫(huà)的時(shí)候圖片初始位置) <img src="../assets/bj.png" alt="" class="bg"> </div> </transition> <button @click="switchMode" style="position:absolute;top:0;left:10px;">start</button> <transition> // 下面播放狀態(tài)框 <div class="mini-player-box" v-show="!fullScreen"> // 狀態(tài)看里面的圖片 (動(dòng)畫(huà)的時(shí)候圖片結(jié)束位置) <div class="mini-img"> <img src="../assets/bj.png" alt="" > </div> </div> </transition> </div> </template>
結(jié)構(gòu)很簡(jiǎn)單,基本就是 兩個(gè)大div ,然后把div的布局按效果圖那些布置。
css部分(省略布局部分)
.cd-box &.v-enter-active, &.v-leave-active transition: all 0.4s &.v-enter, &.v-leave-to opacity: 0 .mini-player-box &.v-enter-active, &.v-leave-active transition: all 0.4s &.v-enter, &.v-leave-to transform: translate3d(0, 40px, 0) opacity: 0
這樣在fullScreen變量改變的時(shí)候,就會(huì)觸發(fā)【過(guò)渡】
這里我們完成第二種動(dòng)畫(huà)
首先安裝插件 , npm i create-keyframe-animation 這個(gè)插件是用js寫(xiě)css的keyframe動(dòng)畫(huà)用的,至于為什么keyframe不在css里面寫(xiě)呢?那是因?yàn)槠聊淮笮〔灰粯樱瑫?huì)導(dǎo)致需要移動(dòng)的px不一樣,所以要?jiǎng)討B(tài)計(jì)算。
給 <transition> 添加動(dòng)畫(huà)鉤子
<transition @enter="enter" @after-enter="afterEnter" @leave="leave" @after-leave="afterLeave" > <div class="cd-box" ref="cdWrapper" v-show="fullScreen"> <img src="../assets/bj.png" alt="" class="bg"> </div> </transition>
計(jì)算偏移量(中心點(diǎn)到中心的偏移,圖中紅線距離)
// 獲得偏移量,以及scale
_getPosAndScale() {
// 左下角圖片的寬度
const targetWidth = 40
// cd寬度
const width = 300
const scale = targetWidth / width
// 這里的 x,y要算,過(guò)程省略,無(wú)非就是加加減減,這的x,y都是算出來(lái)了的
const x = -167.5
const y = 497
return {x ,y , scale}
},
x,y的數(shù)值代表什么?見(jiàn)圖
這里x為什么是負(fù)的,y是正的呢?
因?yàn)?瀏覽器的坐標(biāo)系的中心點(diǎn)是在左上角 的,如圖

那么動(dòng)畫(huà)從 cd中心到左下角,X偏移為負(fù),y偏移為正
然后用animations插件執(zhí)行動(dòng)畫(huà)鉤子
// enter是指當(dāng) cd從隱藏到顯示的動(dòng)畫(huà),
enter(el, done) {
const {x, y, scale} = this._getPosAndScale()
let animation = {
// 第0幀的時(shí)候,先讓圖片縮小,顯示在右下角
0: {
transform: `translate3d(${x}px, ${y}px, 0) scale(${scale})`
},
// 60%的時(shí)候,讓圖片回到cd中心,變大
60: {
transform: `translate3d(0 ,0 , 0) scale(1.1)`
},
// 變回原來(lái)的尺寸,會(huì)有一個(gè)回彈的效果
100: {
transform: `translate3d(0 ,0 , 0) scale(1)`
}
}
// 動(dòng)畫(huà)的一些配置
animations.registerAnimation({
name: 'move',
animation,
presets: {
duration: 400,
easing: 'linear'
}
})
//運(yùn)行動(dòng)畫(huà)
animations.runAnimation(this.$refs.cdWrapper, 'move', done)
},
afterEnter(){
//運(yùn)行完動(dòng)畫(huà)之后,注銷掉動(dòng)畫(huà)
animations.unregisterAnimation('move')
this.$refs.cdWrapper.style.animation = ''
},
// leave是指 cd從顯示到隱藏的動(dòng)畫(huà)
leave(el, done) {
this.$refs.cdWrapper.style.transition = 'all 0.4s'
const {x, y, scale} = this._getPosAndScale()
// 這里我們只要直接移動(dòng)變小就可以了
this.$refs.cdWrapper.style['transform'] = `translate3d(${x}px,${y}px,0) scale(${scale})`
// 監(jiān)聽(tīng)transitionend 事件在 CSS 完成過(guò)渡后觸發(fā)done回調(diào)
this.$refs.cdWrapper.addEventListener('transitionend', () => {
done()
})
},
afterLeave() {
this.$refs.cdWrapper.style.transition = ''
this.$refs.cdWrapper.style['transform'] = ''
}
寫(xiě)到這里,我們就把剛開(kāi)始的效果給寫(xiě)完啦!
但在寫(xiě)js的keyframe的時(shí)候
我們還可以加上rotate,讓動(dòng)畫(huà)效果有一個(gè)回彈效果
let animation = {
0: {
transform: `translate3d(${x}px, ${y}px, 0) scale(${scale}) rotate(0deg)`
},
60: {
transform: `translate3d(0 ,0 , 0) scale(1.1) rotate(365deg)`
},
100: {
transform: `translate3d(0 ,0 , 0) scale(1) rotate(360deg)`
}
}
所有源碼
<template>
<div class="index">
<transition
@enter="enter"
@after-enter="afterEnter"
@leave="leave"
@after-leave="afterLeave"
>
<div class="cd-box" ref="cdWrapper" v-show="fullScreen">
<img src="../assets/bj.png" alt="" class="bg">
</div>
</transition>
<button @click="switchMode" style="position:absolute;top:0;left:10px;">start</button>
<transition>
<div class="mini-box" v-show="!fullScreen">
<div class="mini-img">
<img src="../assets/bj.png" alt="" >
</div>
</div>
</transition>
</div>
</template>
<script>
/* eslint-disable */
import animations from 'create-keyframe-animation'
export default {
components: {},
props: {},
data() {
return {
fullScreen: true
}
},
computed: {},
watch: {},
created() {},
mounted() {
// const {x, y, scale} = this._getPosAndScale()
console.log(this._getPosAndScale())
console.log(animations)
},
methods: {
switchMode() {
this.fullScreen = !this.fullScreen
},
_getPosAndScale() {
const targetWidth = 40
const paddingLeft = 20
const paddingBottom = 20
const paddingTop = 0
const width = 300
const scale = targetWidth / width
const x = -(window.innerWidth / 2 - paddingLeft)
const y = window.innerHeight - paddingTop - paddingBottom - width / 2
return {x ,y , scale}
},
enter(el, done) {
const {x, y, scale} = this._getPosAndScale()
let animation = {
0: {
transform: `translate3d(${x}px, ${y}px, 0) scale(${scale}) rotate(0deg)`
},
60: {
transform: `translate3d(0 ,0 , 0) scale(1.1) rotate(365deg)`
},
100: {
transform: `translate3d(0 ,0 , 0) scale(1) rotate(360deg)`
}
}
animations.registerAnimation({
name: 'move',
animation,
presets: {
duration: 400,
easing: 'linear'
}
})
animations.runAnimation(this.$refs.cdWrapper, 'move', done)
},
afterEnter(){
animations.unregisterAnimation('move')
this.$refs.cdWrapper.style.animation = ''
},
leave(el, done) {
this.$refs.cdWrapper.style.transition = 'all 0.4s'
const {x, y, scale} = this._getPosAndScale()
this.$refs.cdWrapper.style['transform'] = `translate3d(${x}px,${y}px,0) scale(${scale})`
// this.$refs.cdWrapper.style['transform'] = 'rotate(360deg)'
// transitionend 事件在 CSS 完成過(guò)渡后觸發(fā)
this.$refs.cdWrapper.addEventListener('transitionend', () => {
done()
})
},
afterLeave() {
this.$refs.cdWrapper.style.transition = ''
this.$refs.cdWrapper.style['transform'] = ''
}
}
}
</script>
<style lang="stylus" scoped>
.index
background: #eee
width: 100%
height: 100%
display : flex
flex-direction: column
justify-content : space-between
align-items: center
.cd-box
display : flex
justify-content : center
align-items : center
width: 300px
height: 300px
background: #eee
border-radius: 50%
&.v-enter-active, &.v-leave-active
transition: all 0.4s
&.v-enter, &.v-leave-to
opacity: 0
.bg
width: 300px
height: 300px
border-radius: 50%
.mini-box
position: absolute
bottom: 0
right: 0
left: 0
display : flex
align-items center
border: 1px solid #555
width: 100%
height: 40px
box-sizing : border-box
&.v-enter-active, &.v-leave-active
transition: all 0.4s
&.v-enter, &.v-leave-to
transform: translate3d(0, 40px, 0)
opacity: 0
.mini-img
height: 40px
width: 40px
box-sizing : border-box
img
height: 100%
width: 100%
</style>
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
vue+element-ui集成隨機(jī)驗(yàn)證碼+用戶名+密碼的form表單驗(yàn)證功能
在登入頁(yè)面,我們往往需要通過(guò)輸入驗(yàn)證碼才能進(jìn)行登入,那我們下面就詳講一下在vue項(xiàng)目中如何配合element-ui實(shí)現(xiàn)這個(gè)功能,需要的朋友可以參考下2018-08-08
解決vue項(xiàng)目跳轉(zhuǎn)同樣的頁(yè)面不刷新的問(wèn)題思路詳解
做公司官網(wǎng)項(xiàng)目的時(shí)候遇到的場(chǎng)景,頂部導(dǎo)航欄分類商品跳轉(zhuǎn)到分類詳情,然后在分類詳情再次點(diǎn)擊頂部導(dǎo)航欄里另外的分類商品,跳到同樣的頁(yè)面數(shù)據(jù)不刷新,下面小編給大家分享解決方式,關(guān)于vue跳轉(zhuǎn)不刷新問(wèn)題感興趣的朋友一起看看吧2023-09-09
vue項(xiàng)目之?dāng)?shù)量占比進(jìn)度條實(shí)現(xiàn)方式
這篇文章主要介紹了vue項(xiàng)目之?dāng)?shù)量占比進(jìn)度條實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12
一步步帶你用vite簡(jiǎn)單搭建ts+vue3全家桶
Vue3與TS的聯(lián)合是大趨勢(shì),下面這篇文章主要給大家介紹了關(guān)于用vite簡(jiǎn)單搭建ts+vue3全家桶的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-07-07
vue頁(yè)面切換到滾動(dòng)頁(yè)面顯示頂部的實(shí)例
下面小編就為大家分享一篇vue頁(yè)面切換到滾動(dòng)頁(yè)面顯示頂部的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-03-03
vue中的dom節(jié)點(diǎn)和window對(duì)象
這篇文章主要介紹了vue中的dom節(jié)點(diǎn)和window對(duì)象,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04
Vue項(xiàng)目中使用addRoutes出現(xiàn)問(wèn)題的解決方法
大家應(yīng)該都知道可以通過(guò)vue-router官方提供的一個(gè)api-->addRoutes可以實(shí)現(xiàn)路由添加的功能,事實(shí)上就也就實(shí)現(xiàn)了用戶權(quán)限,這篇文章主要給大家介紹了關(guān)于Vue項(xiàng)目中使用addRoutes出現(xiàn)問(wèn)題的解決方法,需要的朋友可以參考下2021-08-08

