Vue圖檔切換過渡效果設計
Time:2021-3-26
前言
不要攔着我!我要先大吹一波Vue,永遠的神!Vue下,不用jQuery!輕松一點代碼和樣式的設計就搞定了圖檔自然過渡的切換!是的,沒有使用vegas.js,沒有使用backstretch.js,沒有任何jQuery插件!咳咳,總之就是非常厲害!
在搭建個人部落格的路上,為了搞這個圖檔自然過渡,可是煩擾了我三天之多啊,終于,在不斷的探索與嘗試之下,找到了最優解(應該是)。
Author:霧雨霜星
歡迎來我的網站學習:
https://www.shuangxing.top/#/passage?id=17
問題的來由
對于圖檔的切換,通過控制src屬性或者設定背景控制style的background-image屬性,可以實作圖檔的切換。但是直接切換,會顯得非常生硬而不自然。是以,我就想尋找圖檔切換過渡的效果。包括:淡入淡出、自然漸變過渡。
可惜啊,網上沒找到好辦法,查到的都是沒什麼通用性的方法或者根本沒效果,别人告訴我的方法都是需要使用jQuery的插件的。
于是,隻好再去研究Vue了。而官方文檔中就要關于過渡和動畫的内容。
環境:VueCLI4.5
關于環境:隻要有Vue包,使用Vue的過渡和動畫都是可以的,環境版本不是特别重要。
官方文檔
- Vue過渡與動畫:https://cn.vuejs.org/v2/guide/transitions.html
- Animate.css官網:http://www.animate.net.cn/
使用原生JS實作圖檔淡入淡出的切換效果
因為使用了Vue,我就沒打算再安裝jQuery了,雖然真的jQuery這麼多插件庫,太香了,但是為了鍛煉自己,還是決定自己挑戰一下,于是我首先想到的就是,使用js,定時器定時切換img的src,然後定時設定透明度,逐漸下降和逐漸提高。
基本思路就是,img的src和style使用v-bind指令綁定,然後在mounted中設定一個周期定時器,定時器中設定定時器來改變目前的透明度,直到透明度為0,改變相應的src變量切換路徑,然後繼續定時修改透明度,使用這種一層又一層的定時器,定時器中設定定時器的方法。
具體的代碼如下:
<template>
<div class="bg">
<img class="HeadImage" :src="HeadImage" :style="ImgStyle"/>
</div>
</template>
<script>
import Wave from "@/components/Wave";
const ImageGroup_DongFang = [
"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(1).png",
"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(2).png",
"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(3).png",
"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(4).png",
"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(5).png",
"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(6).png",
"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(7).png",
"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(8).png",
"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(9).png",
];
export default {
name: "HomeBackground",
data (){
return{
HeadImage:"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(9).png",
ImgStyle:"opacity:1.0",
}
},
methods:{
},
mounted() {
const HeadImageCount = 8;
let StartIntervalTime = 10000;
const ChangeBlankKeepTime = 700;
const ChangeIntervalTime = 500;
const TimeBatisPlus = 1000;
const OpticyStepSize = 0.3;
let _this = this;
let index = 0;
let OpticyIndex = 1.0;
let timer = setInterval(() => {
OpticyIndex = OpticyIndex-OpticyStepSize;_this.ImgStyle = "opacity:"+(OpticyIndex).toString();
setTimeout(() => {OpticyIndex = OpticyIndex-OpticyStepSize;_this.ImgStyle = "opacity:"+(OpticyIndex).toString();
setTimeout(() => {OpticyIndex = OpticyIndex-OpticyStepSize;_this.ImgStyle = "opacity:"+(OpticyIndex).toString();
setTimeout(() => {OpticyIndex = 0;_this.ImgStyle = "opacity:"+(OpticyIndex).toString();
setTimeout(() => {
if(index===HeadImageCount){
index = 0;
}
else{
index = index + 1;
}
setTimeout(() => {OpticyIndex = OpticyIndex+0.1;_this.ImgStyle = "opacity:"+(OpticyIndex).toString();
_this.HeadImage = ImageGroup_DongFang[index];
setTimeout(() => {OpticyIndex = OpticyIndex+OpticyStepSize;_this.ImgStyle = "opacity:"+(OpticyIndex).toString();
setTimeout(() => {OpticyIndex = OpticyIndex+OpticyStepSize;_this.ImgStyle = "opacity:"+(OpticyIndex).toString();
setTimeout(() => {OpticyIndex = 1;_this.ImgStyle = "opacity:"+(OpticyIndex).toString();
setTimeout(() => {
},ChangeIntervalTime);
},ChangeIntervalTime);
},ChangeIntervalTime);
},ChangeIntervalTime);
},ChangeBlankKeepTime);
},ChangeBlankKeepTime);
},ChangeIntervalTime)
},ChangeIntervalTime);
},ChangeIntervalTime+TimeBatisPlus);
}, StartIntervalTime);
},
}
</script>
<style scoped>
.bg{
position: absolute;
top: 0;
left: 0;
width:100%;
z-index: -1;
}
.HeadImage{
width:100%;
transition: all 2s 0s;
}
</style>
簡稱,千層餅!恐怖如斯,看到都開始瑟瑟發抖了吧。
首先使用周期定時器,基本格式如下:
使用了箭頭函數,括号裡面是定時器到逾時後後需要執行的操作,time是定時的時間。
然後先設定了透明度:
注意,我的_this.ImgStyle就是綁定了img元素的style屬性的data變量。
OpticyStepSize是每次變化透明度的步長,OpticyIndex就是計算得到的目前透明度。
然後再設定定時器,逾時後再次變透明度:
setTimeout(() => {OpticyIndex = OpticyIndex-OpticyStepSize;_this.ImgStyle = "opacity:"+(OpticyIndex).toString();
... ...
注意不是周期定時器。
然後後面繼續重複上述操作即可,直到透明度到了你想要的最低,切換路徑:
HeadImage是我綁定了img元素的src屬性的data變量,ImageGroup_DongFang是一個存放了圖檔路徑的數組。
切換後也繼續設定定時器,逐漸提高透明度就可以得到淡入淡出的效果了。
注意可以中間有段時間留白,即透明度為0的時間稍微留長,切換效果會顯得更加好。
效果是有的,而且很明顯,降低每次衰減和增加的透明度,就可以看起來更加連續自然。時間的設定也需要好好測試才行。
Vue過渡與動畫實作圖檔自然切換
正題在此。上面的方法終究是效果看起來欠缺了一些,沒有那麼完美。于是需要尋找更好的方法了。
在Vue的官方文檔中有關于過渡的部分,一開始我覺得,應該沒這麼有用,直到最後才發現,太強了呀!
基本思路:使用Vue的過渡功能實作淡出,使用Vue的動畫功能,結合Animate.css的fadeIn效果來實作淡入功能。另外一說,Animate.css也有淡出的動畫效果,fadeOut。
不得不說,Animate.css配合Vue的過渡元件,真是無敵的組合,使用友善而功能多樣。
我的代碼如下:
<template>
<link href="https://cdn.jsdelivr.net/npm/[email protected]" rel="stylesheet" type="text/css">
<transition name="fade" mode="out-in" enter-active-class="animated fadeIn" :duration="{ enter: 1000, leave: 1000 }">
<img class="img" :src="src_group[0]" v-if="ShowFlagGroup[0] === true" key="img1"/>
</transition>
<transition name="fade" mode="out-in" enter-active-class="animated fadeIn" :duration="{ enter: 1000, leave: 1000 }">
<img class="img" :src="src_group[1]" v-if="ShowFlagGroup[1] === true" key="img2"/>
</transition>
<transition name="fade" mode="out-in" enter-active-class="animated fadeIn" :duration="{ enter: 1000, leave: 1000 }">
<img class="img" :src="src_group[2]" v-if="ShowFlagGroup[2] === true" key="img3"/>
</transition>
<transition name="fade" mode="out-in" enter-active-class="animated fadeIn" :duration="{ enter: 1000, leave: 1000 }">
<img class="img" :src="src_group[3]" v-if="ShowFlagGroup[3] === true" key="img4"/>
</transition>
<transition name="fade" mode="out-in" enter-active-class="animated fadeIn" :duration="{ enter: 1000, leave: 1000 }">
<img id="headimg5" class="img" :src="src_group[4]" v-if="ShowFlagGroup[4] === true" key="img5"/>
</transition>
</template>
<script>
export default {
name: "TransBackGround",
data (){
return{
src_group:[
"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(1).png",
"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(2).png",
"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(3).png",
"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(4).png",
"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(5).png",
],
ShowFlagGroup:[true,false,false,false,false],
show_index:0,
show:true,
}
},
methods:{
},
mounted() {
const img_count=5;
let _this = this;
let index = 0;
let last_index = 0;
let timer = setInterval(() => {
last_index = index;
if(index===img_count-1){
index=0;
}
else {
index = index + 1;
}
_this.ShowFlagGroup[last_index]=false;
_this.ShowFlagGroup[index]=true;
},5000);
}
}
</script>
<style scoped>
.img{
position: absolute;
left: 0;
top: 0;
width: 100%;
}
.fade-enter-active {
transition: all 3s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}
.fade-leave-active {
transition: all 3s cubic-bezier(1.0, 0.5, 0.8, 1.0);
}
.fade-enter, .fade-leave-to {
opacity: 0;
}
</style>
上面之是以使用如此多的img标簽,是因為Vue中 transition标簽的效果要求,要标簽的生成與删除才可以發揮出Vue過渡的效果,是以我這裡給每個圖檔都設定了标簽,這樣就每個圖檔元素單獨設定生成和删除了。自然,機智的我已經想出來不用這麼多img标簽來實作的方法,将在後面記錄。
-
transition标簽的使用:
用途:用于實作元素的過渡效果。具體是,使用v-if指令綁定的元素,在v-if為真和v-if為假時,進行元素生成和删除的過渡效果。
使用方法:直接使用transition标簽,每個裡面隻可以有一個元素(可以多個但是建議不要這樣搞)。
例如:
設定:<transition name="fade" mode="out-in"> <img class="img" :src="src_group[0]" v-if="ShowFlagGroup[0] === true"/> </transition>
-
通過設定過渡的類的樣式來确定具體的過渡效果
包括:v-enter、v-enter-active、v-enter-to、v-leave、v-leave-active、v-leave-to,具體含義見官方文檔說明。
通過在style中設定的,例如:
在相應類中指定相應要使用過渡效果的css樣式即可。.fade-enter-active{ transition: opacity 5s; } .fade-leave-active { transition: opacity 3s; } .fade-leave-to { opacity: 0; }
-
通過設定mode來确定過渡類型
有out-in和in-out兩種,就是确定過渡時,新生成的元素與舊的要被删除的元素,各自過渡效果的先後。
設定如下,直接在标簽中設定,例如:
注意:如果transition标簽設定了name,那麼相應的過渡的class就會變成這樣:name–enter-active
例如,如下因為設定了transition标簽的name是fade,是以相應的過渡的class是:
其餘設定詳見文檔。.fade-enter-active { transition: all 3s cubic-bezier(1.0, 0.5, 0.8, 1.0); }
-
- 引入Animate.css:
- 在過渡标簽中使用Animate.css:
需要在其過渡類中設定,即如上的enter-active-class,然後animated fadeIn即animated + 動畫效果名,該動畫效果名,在Animate.css的官方網站中可以找到。<transition name="fade" mode="out-in" enter-active-class="animated fadeIn"> <img id="headimg5" class="img" :src="src_group[4]" v-if="ShowFlagGroup[4] === true" key="img5"/> </transition>
-
設定動畫時間:
使用duration屬性,例如:
<transition name="fade" mode="out-in" enter-active-class="animated fadeIn" :duration="{ enter: 1000, leave: 1000 }"> <img id="headimg5" class="img" :src="src_group[4]" v-if="ShowFlagGroup[4] === true" key="img5"/> </transition>
-
使用單獨一個img元素:
按照transition标簽的原理,隻要滿足生成(v-if為真)與删除(v-if為假),就可以得到元素的出現與消失的過渡效果。
是以,隻要對一個img标簽不斷切換v-if的值,同時切換其src即可,例如:
<template> <link href="https://cdn.jsdelivr.net/npm/[email protected]" rel="stylesheet" type="text/css"> <transition name="fade" mode="out-in" enter-active-class="animated fadeIn" :duration="{ enter: 1000, leave: 1000 }"> <img class="img" :src="image_url" v-if="image_flag"/> </transition> </template> <script> export default { name: "TransBackGround", data (){ return{ src_group:[ "http://marisa-kirisame.gitee.io/phw/dfheadimg%20(1).png", "http://marisa-kirisame.gitee.io/phw/dfheadimg%20(2).png", "http://marisa-kirisame.gitee.io/phw/dfheadimg%20(3).png", "http://marisa-kirisame.gitee.io/phw/dfheadimg%20(4).png", "http://marisa-kirisame.gitee.io/phw/dfheadimg%20(5).png", ], image_url:"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(5).png", image_flag:true, } }, methods:{ }, mounted() { const img_count=5; let _this = this; let index = 0; let timer = setInterval(() => { if(index===img_count-1){ index=0; } else { index = index + 1; } _this.image_flag=false; setTimeout(() => { _this.image_url = _this.src_group[index]; _this.image_flag=true; },50) },5000); } } </script> <style scoped> .img{ position: absolute; left: 0; top: 0; width: 100%; } .fade-leave-active { transition: all 3s cubic-bezier(1.0, 0.5, 0.8, 1.0); } .fade-leave-to { opacity: 0; } </style>
思路:
在周期定時器中,先令v-if為假值,實作元素删除,進而引發消失的過渡效果,然後一次性定時器中設定,先改變img元素所綁定的src值,然後設定v-if為真,進而引發元素出現的過渡效果。
注意:這個兩次v-if的值的切換,需要保證有一定的時間間隔差,否則會看不出過渡效果。我上述例子中使用了定時器setTimeout。
-
注意:
經過測試,如果隻使用單獨一個元素,那麼隻可以做淡入淡出的過渡效果。如果使用上述說的多個元素,那麼可以做自然過渡效果。這種自然過渡效果,是一種圖檔的漸變效果,沒有太對透明度的直接變化。
Vue動畫實作圖檔切換過渡效果
經過測試确定,不使用transition标簽的過渡,僅使用Animate.css動畫的FadeIn和FadeOut動畫效果,配合可以實作比較完美的淡入淡出或者自然過渡效果。
注意:以下的例子與上述的自然過渡不同,是淡入淡出,在動畫的效果中,切換間,中間一小段是可能會留白的。
代碼如下:
<template>
<link href="https://cdn.jsdelivr.net/npm/[email protected]" rel="stylesheet" type="text/css">
<transition name="fade" mode="out-in"
leave-active-class="animated fadeOut" enter-active-class="animated fadeIn"
:duration="{ enter: 1000, leave: 1000 }">
<img class="img" :src="image_url" v-if="image_flag"/>
</transition>
</template>
<script>
export default {
name: "TransBackGround",
data (){
return{
src_group:[
"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(1).png",
"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(2).png",
"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(3).png",
"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(4).png",
"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(5).png",
],
image_url:"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(5).png",
image_flag:true,
}
},
methods:{
},
mounted() {
const img_count=5;
let _this = this;
let index = 0;
let last_index = 0;
let timer = setInterval(() => {
last_index = index;
if(index===img_count-1){
index=0;
}
else {
index = index + 1;
}
_this.image_flag=false;
setTimeout(() => {
_this.image_url = _this.src_group[index];
_this.image_flag=true;
},10)
},5000);
}
}
</script>
<style scoped>
.img{
position: absolute;
left: 0;
top: 0;
width: 100%;
}
</style>
-
思路:
設定transition标簽的leave-active-class指定為Animate.css的fadeOut,設定enter-active-class為Animate.css的fadeIn,然後設定屬性 duration來指定兩個動畫的産生效果時間。
即關鍵一步隻有:
<transition name="fade" mode="out-in"
leave-active-class="animated fadeOut" enter-active-class="animated fadeIn"
:duration="{ enter: 1000, leave: 1000 }">
... ...
同理,我這裡也是隻使用一個img元素,在周期定時器中間隔一小段時間,來回重置v-if實作transition标簽過渡起效果。即:
_this.image_flag=false;
setTimeout(() => {
_this.image_url = _this.src_group[index];
_this.image_flag=true;
},10)
需要注意的是,duration屬性的設定對效果起到非常關鍵的作用。時間太長會發現留白較多,時間太短會發現幾乎看不出過渡效果。在上述例子中給出了較為完美的設定時間:
:duration="{ enter: 1000, leave: 1000 }"
該屬性還需要花費一些時間去調整,進而達到自己想要的效果。
Vue動畫自然過渡效果:
上述例子之是以是淡入淡出,是因為隻使用了一個img元素來做過渡,如果使用多個img元素來做過渡,那麼就可以實作自然過渡。
代碼如下:
<template>
<link href="https://cdn.jsdelivr.net/npm/[email protected]" rel="stylesheet" type="text/css">
<transition name="fade" mode="out-in"
leave-active-class="animated fadeOut" enter-active-class="animated fadeIn" >
<img class="img" :src="src_group[0]" v-if="ShowFlagGroup[0] === true"/>
</transition>
<transition name="fade" mode="out-in"
leave-active-class="animated fadeOut" enter-active-class="animated fadeIn" >
<img class="img" :src="src_group[1]" v-if="ShowFlagGroup[1] === true"/>
</transition>
<transition name="fade" mode="out-in"
leave-active-class="animated fadeOut" enter-active-class="animated fadeIn" >
<img class="img" :src="src_group[2]" v-if="ShowFlagGroup[2] === true"/>
</transition>
<transition name="fade" mode="out-in"
leave-active-class="animated fadeOut" enter-active-class="animated fadeIn" >
<img class="img" :src="src_group[3]" v-if="ShowFlagGroup[3] === true"/>
</transition>
<transition name="fade" mode="out-in"
leave-active-class="animated fadeOut" enter-active-class="animated fadeIn">
<img class="img" :src="src_group[4]" v-if="ShowFlagGroup[4] === true"/>
</transition>
</template>
<script>
export default {
name: "TransBackGround",
data (){
return{
src_group:[
"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(1).png",
"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(2).png",
"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(3).png",
"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(4).png",
"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(5).png",
],
ShowFlagGroup:[true,false,false,false,false],
show_index:0,
}
},
methods:{
},
mounted() {
const img_count=5;
let _this = this;
let index = 0;
let last_index = 0;
let timer = setInterval(() => {
last_index = index;
if(index===img_count-1){
index=0;
}
else {
index = index + 1;
}
_this.ShowFlagGroup[last_index]=false;
_this.ShowFlagGroup[index]=true;
},5000);
}
}
</script>
<style scoped>
.img{
position: absolute;
left: 0;
top: 0;
width: 100%;
}
</style>
同理,使用transition标簽的leave-active-class屬性與enter-active-class屬性綁定為fadeOut與的動畫效果。
更新:因為自然過渡的速度并不一定使我們想要的,那麼可以通過設定定時器,确定一個時間間隔來分開兩個元素的切換。
在周期定時器的對元素進行切換時,加入定時器,代碼如下:
_this.ShowFlagGroup[last_index]=false;
setTimeout(() => {
_this.ShowFlagGroup[index]=true;
},50)
通過調節setTimeout的逾時時間,可以讓我們有更大的調節空間來設定自然過渡的效果。
這個方法的好處是,時間間隔較大時(例如我測試的:500),就是淡入淡出了,可以說是囊括了兩種圖檔切換過渡,隻要調節定時器的逾時時間,就可以設定到自己想要的圖檔切換的過渡效果。
最終代碼如下:
<template>
<link href="https://cdn.jsdelivr.net/npm/[email protected]" rel="stylesheet" type="text/css">
<transition name="fade" mode="out-in"
leave-active-class="animated fadeOut" enter-active-class="animated fadeIn" >
<img class="img" :src="src_group[0]" v-if="ShowFlagGroup[0] === true"/>
</transition>
<transition name="fade" mode="out-in"
leave-active-class="animated fadeOut" enter-active-class="animated fadeIn" >
<img class="img" :src="src_group[1]" v-if="ShowFlagGroup[1] === true"/>
</transition>
<transition name="fade" mode="out-in"
leave-active-class="animated fadeOut" enter-active-class="animated fadeIn" >
<img class="img" :src="src_group[2]" v-if="ShowFlagGroup[2] === true"/>
</transition>
<transition name="fade" mode="out-in"
leave-active-class="animated fadeOut" enter-active-class="animated fadeIn" >
<img class="img" :src="src_group[3]" v-if="ShowFlagGroup[3] === true"/>
</transition>
<transition name="fade" mode="out-in"
leave-active-class="animated fadeOut" enter-active-class="animated fadeIn">
<img class="img" :src="src_group[4]" v-if="ShowFlagGroup[4] === true"/>
</transition>
</template>
<script>
export default {
name: "TransBackGround",
data (){
return{
src_group:[
"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(1).png",
"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(2).png",
"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(3).png",
"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(4).png",
"http://marisa-kirisame.gitee.io/phw/dfheadimg%20(5).png",
],
ShowFlagGroup:[true,false,false,false,false],
show_index:0,
}
},
methods:{
},
mounted() {
const img_count=5;
let _this = this;
let index = 0;
let last_index = 0;
let duration_time = 50;
let timer = setInterval(() => {
last_index = index;
if(index===img_count-1){
index=0;
}
else {
index = index + 1;
}
_this.ShowFlagGroup[last_index]=false;
setTimeout(() => {
_this.ShowFlagGroup[index]=true;
},duration_time)
},5000);
}
}
</script>
<style scoped>
.img{
position: absolute;
left: 0;
top: 0;
width: 100%;
}
</style>
至此,對圖檔切換的研究也差不多了。
存在問題
到目前為止,我還沒有通過僅使用transition标簽的過渡,不使用動畫,來實作圖檔的淡入淡出或者自然過渡。隻使用Vue過渡,我隻實作了淡出,但是淡入一直沒有成功。如果有人成功了,來教教我,填個坑!
轉載請注明出處!!!
Author:霧雨霜星
歡迎來我的網站學習:
https://www.shuangxing.top/#/passage?id=17
Thanks!
PS: 畢竟,霜星醬水準有限,如果發現任何錯誤還請及時郵箱告知我,我會去改哦!