uniapp定義動(dòng)畫的幾種方式總結(jié)
本章的前提就是大家都知道動(dòng)畫的基本屬性,例如animation-name、animation-duration、animation-timing-function、animation-delay、animation-iteration-count和animation-direction 屬性。
了解更多 animation 相關(guān)的內(nèi)容。
現(xiàn)在制作一個(gè)左右抖動(dòng)的動(dòng)畫效果,效果如下:

在 uniapp 中,可以通過如下兩種方式來完成。
1. 直接使用 CSS 動(dòng)畫
1.1 定義動(dòng)畫
@keyframes shakeX {
from,
to {
transform: translate3d(0, 0, 0);
}
10%,
30%,
50%,
70%,
90% {
transform: translate3d(-10px, 0, 0);
}
20%,
40%,
60%,
80% {
transform: translate3d(10px, 0, 0);
}
}
.shakeX {
animation-name: shakeX;
animation-duration: 1s;
}1.2 使用
<view class="box shakeX"></view>
<style>
.box {
width: 100rpx;
height: 100rpx;
background-color: green;
}
</style>效果如下:

2. 通過 uniapp 提供編程式創(chuàng)建動(dòng)畫
uniapp 提供 createAnimation 內(nèi)置函數(shù),用于創(chuàng)建一個(gè)動(dòng)畫實(shí)例 animation。
動(dòng)畫定義步驟:
- 創(chuàng)建動(dòng)畫實(shí)例
- 調(diào)用實(shí)例的方法來描述動(dòng)畫
- 通過動(dòng)畫實(shí)例的
export方法導(dǎo)出動(dòng)畫數(shù)據(jù) - 導(dǎo)出的動(dòng)畫數(shù)據(jù)傳遞給組件的
animation屬性(uniapp 提供組件都支持 animation 屬性)
兼容性列表:
| App | H5 | 微信小程序 | 支付寶小程序 | 百度小程序 | 字節(jié)跳動(dòng)小程序、飛書小程序 | QQ小程序 | 快手小程序 | 京東小程序 | |
|---|---|---|---|---|---|---|---|---|---|
| √ | HBuilderX 2.0.4+ | √ | √ | √ | √ | √ | x | x |
注意??:
export方法每次調(diào)用后會(huì)清掉之前的動(dòng)畫操作。nvue暫不支持
2.1 定義動(dòng)畫
接下來通過編程實(shí)現(xiàn)上面抖動(dòng)功能。
2.1.1 創(chuàng)建動(dòng)畫實(shí)例
const animation = uni.createAnimation(); // 定義動(dòng)畫實(shí)例
2.1.2 調(diào)用實(shí)例方法來描述動(dòng)畫
在上面的 shakeX 動(dòng)畫定義中,通過 translate3d 來定義動(dòng)畫。 對(duì)應(yīng)的在 animation 實(shí)例中去查找與 translate3d 相關(guān)的實(shí)例方法。
translate 相關(guān)的實(shí)例方法,如下:
| 方法 | 參數(shù) | 說明 |
|---|---|---|
| translate | tx,[ty] | 一個(gè)參數(shù)時(shí),表示在X軸偏移tx,單位px;兩個(gè)參數(shù)時(shí),表示在X軸偏移tx,在Y軸偏移ty,單位px。 |
| translateX | tx | 在X軸偏移tx,單位px |
| translateY | ty | 在Y軸偏移ty,單位px |
| translateZ | tz | 在Z軸偏移tz,單位px |
| translate3d | (tx,ty,tz) | 在X軸偏移tx,在Y軸偏移ty,在Z軸偏移tz,單位px |
有了這些方法之后,我們可以描述動(dòng)畫啦~
@keyframes shakeX {
from,
to {
transform: translate3d(0, 0, 0);
}
10%,
30%,
50%,
70%,
90% {
transform: translate3d(-10px, 0, 0);
}
20%,
40%,
60%,
80% {
transform: translate3d(10px, 0, 0);
}
}上面 CSS 中 translate3d,對(duì)應(yīng)到編程方式如下:
animation.translate3d(0, 0, 0); // 原始位置 animation.translate3d(-10, 0, 0); // 向左偏移 animation.translate3d(10, 0, 0); // 像右偏移
有上面方法后,可以把動(dòng)畫描述出來,如下:
animation.animation3d(0, 0, 0) // 0%
.animation3d(-10, 0, 0) // 10%
.animation3d(10, 0, 0) // 20%
.animation3d(-10, 0, 0) // 30%
// ...
.animation3d(0, 0, 0); // 100%現(xiàn)在通過 export() 方法導(dǎo)出定義動(dòng)畫:
<template>
<view class="box" :animation="animationData"></view>
</template>export default {
data() {
return {
animationData: {}
}
},
onLoad(){
const animation = uni.createAnimation();
animation.animation3d(0, 0, 0) // 0%
.animation3d(-10, 0, 0) // 10%
.animation3d(10, 0, 0) // 20%
.animation3d(-10, 0, 0) // 30%
// ...
.animation3d(0, 0, 0); // 100%
this.animationData = animation.export();
}
}代碼運(yùn)行之后,并沒有如期出現(xiàn)預(yù)期抖動(dòng)效果。為什么? 因?yàn)?nbsp;uniapp 中在定義的一組動(dòng)畫中是并行執(zhí)行的,所以并不會(huì)產(chǎn)生動(dòng)畫效果。
再回過來,看上面 CSS 中把一個(gè)動(dòng)畫周期劃分成不同的組(步驟),10% 時(shí)執(zhí)行 translate3d(-10px, 0, 0),20% 時(shí)執(zhí)行translate3d(10px, 0, 0)。
在 uni-app 中有沒有類似的方式呢? 通過 step 來定義。
animation
.translateX(0) // 0%
.translateX(10) // 20%
.step();
animation.translateX(-10).step(); // 30%
animation.translateX(10).step(); // 40%
animation.translateX(-10).step(); // 50%
animation.translateX(10).step(); // 60%
animation.translateX(-10).step(); // 70%
animation.translateX(10).step(); // 80%
animation.translateX(-10).step(); // 90%
animation.translateX(0).step(); // 100%
this.animationData = animation.export();再來執(zhí)行代碼,發(fā)現(xiàn)會(huì)動(dòng)了。

從效果來看發(fā)現(xiàn)跟預(yù)期效果差很多,為什么? 跟 animation 的 animation-duration 屬性有關(guān)。
animation-duration: 屬性指定一個(gè)動(dòng)畫周期的時(shí)長(zhǎng)。
也就是一組動(dòng)畫運(yùn)行完所需時(shí)間。 在 uni.createAnimation() 創(chuàng)建動(dòng)畫時(shí)可以傳遞參數(shù),在不顯示的指定 duration 值時(shí),默認(rèn)值為 400ms。 而 step() 會(huì)繼承該值。
| 參數(shù) | 類型 | 必填 | 默認(rèn)值 | 說明 | |
|---|---|---|---|---|---|
| duration | Integer | 否 | 400 | 動(dòng)畫持續(xù)時(shí)間,單位ms | |
| timingFunction | String | 否 | "linear" | 定義動(dòng)畫的效果 | |
| delay | Integer | 否 | 0 | 動(dòng)畫延遲時(shí)間,單位 ms | |
| transformOrigin | String | 否 | "50% 50% 0" | 設(shè)置transform-origin |
這就是 “慢” 的原因。
在明白“慢”之后,只要把動(dòng)畫執(zhí)行時(shí)間 (duration) 調(diào)整,應(yīng)該能看到預(yù)期效果。假設(shè)期望完成抖動(dòng)時(shí)間 1s,把動(dòng)畫拆分成 10 組,則每一組的動(dòng)畫時(shí)間為 100 ms.
現(xiàn)在指定 step 的 duration 值為 100ms,更改后代碼如下:
animation
.translateX(0) // 0%
.translateX(10) // 20%
.step({
duration: 100,
});
animation.translateX(-10).step({
duration: 100,
}); // 30%
animation.translateX(10).step({
duration: 100,
}); // 40%
animation.translateX(-10).step({
duration: 100,
});
// 50%
animation.translateX(10).step({
duration: 100,
}); // 60%
animation.translateX(-10).step({
duration: 100,
}); // 70%
animation.translateX(10).step({
duration: 100,
}); // 80%
animation.translateX(-10).step({
duration: 100,
}); // 90%
animation.translateX(0).step({
duration: 100,
});
this.animationData = animation.export();再來執(zhí)行代碼,運(yùn)行效果如下:

發(fā)現(xiàn)效果基本與預(yù)期效果一樣了。
更多 uni.createAnimation() 相關(guān)的內(nèi)容,可以自行查看文檔
3. 什么情況下使用編程式創(chuàng)建動(dòng)畫
當(dāng)不能通過 css 方式或通過動(dòng)態(tài)類名一些方式去添加動(dòng)畫時(shí),此時(shí)就可以考慮使用編程式來創(chuàng)建動(dòng)畫。編程式可以很靈活創(chuàng)建動(dòng)畫、控制動(dòng)畫運(yùn)行和監(jiān)聽動(dòng)畫的結(jié)束。 其次從兼容列表來看,能很好在不同平臺(tái)運(yùn)行。
現(xiàn)在看個(gè)實(shí)際例子: 在登錄時(shí),通常需要 ?? 選用戶協(xié)議和隱私政策 之后才允許用戶登錄。現(xiàn)在產(chǎn)品希望當(dāng)用戶在未勾選時(shí)點(diǎn)擊登錄,希望通過抖動(dòng) 用戶協(xié)議和隱私政策來提醒用戶。

上面需求需要完成幾個(gè)功能點(diǎn):
- 定義抖動(dòng)動(dòng)畫類
- 未勾選時(shí)動(dòng)態(tài)添加動(dòng)畫類
- 動(dòng)畫結(jié)束時(shí)移除動(dòng)畫類(用戶下一次點(diǎn)擊時(shí),需要繼續(xù)抖動(dòng))
通常可以這樣做:
<view ref="agreement" class="agreement" :class="{ 'shakeX': actived }">
<radio
@click="onChecked"
style="transform: scale(0.6)"
:color="color"
:checked="agreement"
></radio>
我已閱讀并同意<text class="service"
>用戶協(xié)議</text
>和<text class="privacy">隱私政策</text>
</view>
<button @click="onLogin">登錄</button>export default {
data() {
return {
actived: false // false
};
},
mounted(){
this.$refs.agreement.$el.addEventListener("animationend", ()=> {
this.actived = false; // 動(dòng)畫結(jié)束移除類
});
},
methods: {
onLogin(){
// 動(dòng)態(tài)添加
this.actived = true;
}
},
};@keyframes shakeX {
from,
to {
transform: translate3d(0, 0, 0);
}
10%,
30%,
50%,
70%,
90% {
transform: translate3d(-10px, 0, 0);
}
20%,
40%,
60%,
80% {
transform: translate3d(10px, 0, 0);
}
}
.shakeX {
animation-name: shakeX;
animation-duration: 1s;
}發(fā)現(xiàn)在 app、小程序 上運(yùn)行時(shí),發(fā)現(xiàn) this.$refs.agreement.$el 為空,這是為什么,這里就是跟 uniapp 底層設(shè)計(jì)有關(guān),如下圖所示:

上面引用微信小程序,uniapp 在設(shè)計(jì)跟小程序是一樣的。 也可以在上底層設(shè)計(jì)鏈接中了解到 uniapp 設(shè)計(jì)。
如果不能獲取元素并注冊(cè)animationend事件,沒辦法很好知道動(dòng)畫結(jié)束,不知道何時(shí)應(yīng)該移除。當(dāng)然有的人想可以通過定時(shí)器完成,這樣不能精細(xì)話控制。
此時(shí)通過編程式就可以很好解決兼容的問題,現(xiàn)在稍微調(diào)整下:
<view class="agreement" :animation="animationData">
<radio
@click="onChecked"
style="transform: scale(0.6)"
:color="color"
:checked="agreement"
></radio>
我已閱讀并同意<text class="service"
>用戶協(xié)議</text
>和<text class="privacy">隱私政策</text>
</view>
<button @click="onLogin">登錄</button>export default {
data() {
return {
animationData: {}
};
},
onLoad(){
const animation = uni.createAnimation({
timingFunction: "linear",
});
this.animation = animation;
},
methods: {
shakeX() {
const animation = this.animation;
animation
.translateX(0) // 0%
.translateX(10) // 20%
.step({
duration: 100,
});
animation.translateX(-10).step({
duration: 100,
}); // 30%
animation.translateX(10).step({
duration: 100,
}); // 40%
animation.translateX(-10).step({
duration: 100,
});
// 50%
animation.translateX(10).step({
duration: 100,
}); // 60%
animation.translateX(-10).step({
duration: 100,
}); // 70%
animation.translateX(10).step({
duration: 100,
}); // 80%
animation.translateX(-10).step({
duration: 100,
}); // 90%
animation.translateX(0).step({
duration: 100,
});
this.animationData = animation.export();
},
onLogin(){
this.shakeX();
}
},
};通過編程方式,為什么不需要像動(dòng)態(tài)類名的方式,動(dòng)畫結(jié)束必須移除類名否則下次不會(huì)生效? 這里留給大家去思考了。
4. 總結(jié)
- 具體采用哪種方式創(chuàng)建動(dòng)畫,可以根據(jù)實(shí)際業(yè)務(wù)場(chǎng)景來定。
- uniapp 編程方式,通過
step來進(jìn)行動(dòng)畫分組,同一個(gè)分組內(nèi)動(dòng)畫函數(shù)會(huì)并行執(zhí)行。 - 多個(gè)動(dòng)畫分組之間的執(zhí)行是串行的,也就是需等待上一個(gè)結(jié)束才會(huì)執(zhí)行下一個(gè)。
到此這篇關(guān)于uniapp定義動(dòng)畫的幾種方式的文章就介紹到這了,更多相關(guān)uniapp定義動(dòng)畫方式內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Javascript 阿拉伯?dāng)?shù)字轉(zhuǎn)化中國(guó)大寫數(shù)字的函數(shù)代碼
將阿拉伯?dāng)?shù)字轉(zhuǎn)化中國(guó)大寫數(shù)字的函數(shù)代碼,需要的朋友可以參考下。2010-04-04
詳解JavaScript基于面向?qū)ο笾^承實(shí)例
這篇文章主要介紹了JavaScript基于面向?qū)ο笾^承實(shí)例,需要的朋友可以參考下2015-12-12
JS判斷傳入函數(shù)的參數(shù)是否為空(函數(shù)參數(shù)是否傳遞)
這篇文章主要介紹了JS判斷傳入函數(shù)的參數(shù)是否為空(函數(shù)參數(shù)是否傳遞),需要的朋友可以參考下2023-05-05
js 函數(shù)的執(zhí)行環(huán)境和作用域鏈的深入解析
在js中對(duì)象的外在表現(xiàn)形式為函數(shù)。2009-11-11
JavaScript實(shí)現(xiàn)鼠標(biāo)移動(dòng)事件畫筆
這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)鼠標(biāo)移動(dòng)事件畫筆,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08

