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寫css的keyframe動(dòng)畫(huà)用的,至于為什么keyframe不在css里面寫呢?那是因?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'] = ''
}
寫到這里,我們就把剛開(kāi)始的效果給寫完啦!
但在寫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)文章
vue2基本響應(yīng)式實(shí)現(xiàn)方式之讓數(shù)組也變成響應(yīng)式
這篇文章主要介紹了vue2基本響應(yīng)式實(shí)現(xiàn)方式之讓數(shù)組也變成響應(yīng)式問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04
Vue3之toRefs和toRef在reactive中的一些應(yīng)用方式
這篇文章主要介紹了Vue3之toRefs和toRef在reactive中的一些應(yīng)用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03
vue實(shí)現(xiàn)的上傳圖片到數(shù)據(jù)庫(kù)并顯示到頁(yè)面功能示例
這篇文章主要介紹了vue實(shí)現(xiàn)的上傳圖片到數(shù)據(jù)庫(kù)并顯示到頁(yè)面功能,結(jié)合實(shí)例形式分析了基于vue.js的數(shù)據(jù)庫(kù)操作及頁(yè)面圖片顯示相關(guān)操作技巧,需要的朋友可以參考下2018-03-03
vue中用H5實(shí)現(xiàn)文件上傳的方法實(shí)例代碼
本篇文章主要介紹了vue中用H5實(shí)現(xiàn)文件上傳的方法實(shí)例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-05-05
vue實(shí)現(xiàn)動(dòng)態(tài)路由的方法及路由原理解析
這篇文章主要介紹了路由原理及vue實(shí)現(xiàn)動(dòng)態(tài)路由,Vue Router 提供了豐富的 API,可以輕松地實(shí)現(xiàn)路由功能,并支持路由參數(shù)、查詢參數(shù)、命名路由、嵌套路由等功能,可以滿足不同應(yīng)用程序的需求,需要的朋友可以參考下2023-06-06
vue?LogicFlow更多配置選項(xiàng)示例詳解
這篇文章主要為大家介紹了vue?LogicFlow更多配置選項(xiàng)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
vue項(xiàng)目中vue-i18n和element-ui國(guó)際化開(kāi)發(fā)實(shí)現(xiàn)過(guò)程
這篇文章主要介紹了vue項(xiàng)目中vue-i18n和element-ui國(guó)際化開(kāi)發(fā)實(shí)現(xiàn)過(guò)程,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2018-04-04

