Web Animations 與 Angular動畫
標簽: angular javascript css web
什么是Web Animations
概述
正如CSS Animations一樣,Web Animations
是javascript提供的一組動畫接口,它允許同步和定時更改網頁的呈現, 即DOM元素的動畫。因此,使用Web Animations
可以方便地用Js操作動畫,而不再需要像之前那樣寫一大堆css和定時器來實現。
兼容性
它目前尚屬W3C的標準草案,詳情可查閱:https://www.w3.org/TR/web-animations/ ,因此很多瀏覽器并不能完整支持,
正因如此,W3C官方為開發者提供了web-animations/web-animations-js
polyfill插件,是我們能通過插件來解決瀏覽器的支持問題,插件地址:https://github.com/web-animations/web-animations-js/tree/master
<script src="web-animations.min.js"></script>
如上所示插入插件,即可使用Web Animations進行開發。
代碼示例
提供了很簡潔明了的,我們可以在 dom 元素上直接調用的 animate 函數:
var element = document.querySelector('.animate-me');
var animation = element.animate(keyframes, 1000);
第一個參數是一個對象數組,每個對象表示動畫中的一幀:
var keyframes = [
{ opacity: 0 },
{ opacity: 1 }
];
這與 css 中的 keyframe 定義類似:
0% {
opacity: 0;
}
100% {
opacity: 1;
}
第二個參數是 duration,表示動畫的時間。同時也支持在第二個參數中傳入配置項來指定緩動方式、循環次數等:
var options = {
iterations: Infinity, // 動畫的重復次數,默認是 1
iterationStart: 0, // 用于指定動畫開始的節點,默認是 0
delay: 0, // 動畫延遲開始的毫秒數,默認 0
endDelay: 0, // 動畫結束后延遲的毫秒數,默認 0
direction: 'alternate', // 動畫的方向 默認是按照一個方向的動畫,alternate 則表示交替
duration: 700, // 動畫持續時間,默認 0
fill: 'forwards', // 是否在動畫結束時回到元素開始動畫前的狀態
easing: 'ease-out', // 緩動方式,默認 "linear"
};
var animation = element.animate(keyframes, options);
在 dom 元素上調用 animate 函數之后返回一個 Animation
對象,或者通過 ele.getAnimation
方法獲取 dom 上的 Animation
對象。
Animation
對象有一些屬性和方法,比如:
Animation.finished
(此動畫的當前完成的狀態,只讀)Animation.effect
(與此動畫相關聯的關鍵幀)Animation.play()
(開始播放動畫)Animation.pause()
(暫停播放動畫)
等等。
Animation
對象還有兩個事件處理程序:
Animation.oncancel
:獲取并設置取消事件的事件處理程序Animation.onfinish
:獲取并設置完成事件的事件處理程序
由以上API,開發者可以通過 promise
和 event
兩種方式對動畫進行操作:
// 通過監聽事件進行處理
myAnimation.onfinish = function() {
element.remove();
}
// 通過承諾進行處理
myAnimation.finished.then(
() => element.remove()
)
與CSS動畫相比的優點
低耦合
CSS 動畫中,如果需要控制動畫或者過渡的開始或結束只能通過相應的 dom 事件來監聽,并且在回調函數中操作,這也是受 CSS 本身語言特性約束所致。也就是說很多情況下,想要完成一個動畫需要結合 CSS 和 JS 來共同完成。使用 WAAPI 則有 promise 和 event 兩種方式與監聽 dom 事件相對應。從代碼可維護性和完整性上看 WAAPI 有自身語言上的優勢。
兼容性和流暢度
事實上Web Animations
常用方法現在已經兼容了大部分現代的瀏覽器。如果想現在就玩玩,可以使用官方提供的polyfill。而CSS動畫我們也用了很久,基本上對于老舊的瀏覽器只能用一些優雅的降級方案。至于流暢度的問題兩者性能差距不大,而且Web Animations
提供了性能優化的方案。
Angular中的Web Animations動畫
概述,及引入方法
Angular動畫是基于標準的Web動畫API(Web Animations API)構建的,它們在支持此API的瀏覽器中會用原生方式工作。
上述是官方文檔對于Angular動畫的解釋。由于基于Web Animations,因此很多寫法也是非常相像的。
和http、form一樣,Angular中的動畫也是一個獨立模塊,首先需在根模塊進行導入:
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
// ...(其它模塊)
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserAnimationsModule,
// ...(其它模塊)
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
就在組件里去定義動畫了,如果需要定義大量的動畫片段,建議單獨建立一個項目的動畫模塊。當然,定義動畫之前需要引入一些常用的API:
import { trigger, state, style, transition, animate, keyframes } from '@angular/animations';
基本寫法
import {
Component,
Input
} from '@angular/core';
import {
trigger,
state,
style,
animate,
transition
} from '@angular/animations';
@Component({
selector: 'app-hero-list-basic',
template: `
<h1 [@clickAnim]="state"
(click)="toggleState()">
點擊觸發
</h1>
`,
styleUrls: [],
animations: [
trigger('clickAnim', [
state('inactive', style({
backgroundColor: '#eee',
transform: 'scale(1)'
})),
state('active', style({
backgroundColor: '#cfd8dc',
transform: 'scale(1.1)'
})),
transition('inactive => active', animate('100ms ease-in')),
transition('active => inactive', animate('100ms ease-out'))
])
]
})
export class HeroListBasicComponent {
constructor(public state = 'inactive') { }
toggleState() {
this.state = this.state === 'active' ? 'inactive' : 'active';
}
}
上述代碼在@Component元數據中構建了一個名為clickAnim的簡單動畫,它會讓<h1>
元素在兩個狀態active
和inactive
之間轉場, 當處于active**狀態時,它會把該元素顯示得稍微大一點、亮一點。模板中用[@triggerName]
語法即可調用。
狀態(state)
在此動畫中,我們可以為每個動畫狀態定義了一組樣式:
state('inactive', style({
backgroundColor: '#eee',
transform: 'scale(1)'
})),
state('active', style({
backgroundColor: '#cfd8dc',
transform: 'scale(1.1)'
})),
這些state
具體定義了每個狀態的最終樣式,也就是說,這里其實并不只是在定義動畫,而是在定義該元素在不同狀態時應該具有的樣式。
除了自定義狀態,還有兩種特殊狀態:
- void:匹配尚未被添加進來或者已經被移除了的狀態,用于進場或離場動畫
- *:匹配任何動畫的狀態
transition()
而負責這定義兩組樣式轉換的則是transition()
函數,它的第一個參數負責定義需被轉換的狀態名稱(可定義多個):
transition('inactive => active', animate('100ms ease-in')),
transition('active => inactive', animate('100ms ease-out'))
其中,=>
也可以寫成 <=>
即雙向的。
第二個參數是一個animate()
函數或一個數組,負責定義動畫執行的總時間以及樣式,當有些樣式只希望在動畫過程中生效,結束后并不保留,可以在數組中定義一個style()
函數:
transition('inactive => active', [
style({
backgroundColor: '#cfd8dc',
transform: 'scale(1.3)'
}),
animate(
'80ms ease-in',
style({
backgroundColor: '#eee',
transform: 'scale(1)'
})
)
]),
關鍵幀
上述代碼中,關于動畫運行的方式,用了ease-in
和ease-out
兩種方法,除此之外還有幾種,例如linear
等,同CSS動畫一樣,甚至可以使用一些賽貝爾曲線,例如cubic-bezier(0.4, 0, 0.2, 1)
。我們可以在這兩個網站自定義挑選賽貝爾曲線的表達式:
同CSS一樣,并不是所有的賽貝爾曲線都能被使用的,所以關鍵幀的設置必不可少,它在Angular中是這樣寫的:
transition('* => void', [
animate(300, keyframes([
style({
opacity: 1,
transform: 'translateX(0)',
offset: 0
}),
style({
opacity: 1,
transform: 'translateX(-15px)',
offset: 0.7
}),
style({
opacity: 0,
transform: 'translateX(100%)',
offset: 1.0
})
]))
])
上述代碼是一個典型的“離場動畫”,它在第二幀定義了一些“反彈”效果。
offset
屬性定義了此幀在整個動畫中處于哪個時間點,它并不一定用絕對數字定義,而是在0到1之間的相對值(百分比),而且它是可選的,如果省略它,偏移量會自動根據幀數平均分布出來。
第三方動畫庫
上述的動畫我們直接寫在了組件中,更多時候往往需要把它們抽象出來,形成一個自己的動畫庫,可以在各個組件調用。下面這個簡單的庫來自于segmentfault社區:
// animate.ts
import {
trigger,
state,
style,
transition,
animate,
keyframes
} from '@angular/animations';
// 動畫時間線
var time = '300ms'
var styles = {
ease: time + ' ease ',
linear: time + ' linear ',
easeIn: time + ' ease-in',
easeOut: time + ' ease-out',
stepStart: time + ' step-start',
stepEnd: time + ' step-end',
easeInOut: time + ' ease-in-out',
faseOutSlowIn: time + ' cubic-bezier(0.4, 0, 0.2, 1)',
inOutBack: time + ' cubic-bezier(0.68, -0.55, 0.27, 1.55)',
inOutCubic: time + ' cubic-bezier(0.65, 0.05, 0.36, 1)',
inOutQuadratic: time + ' cubic-bezier(0.46, 0.03, 0.52, 0.96)',
inOutSine: time + ' cubic-bezier(0.45, 0.05, 0.55, 0.95)'
}
// 動畫配置
var opts = {
fadeIn: [
style({ opacity: 0 }),
animate(styles.inOutBack, style({ opacity: 1 })),
],
fadeOut: [
style({ opacity: 1 }),
animate(styles.inOutBack, style({ opacity: 0 }))
],
shrink: [
style({ height: '*' }),
animate(styles.inOutBack, style({ height: 0 }))
],
stretch: [
style({ height: '0' }),
animate(styles.inOutBack, style({ height: '*' }))
],
flyIn: [
style({ transform: 'translateX(-100%)' }),
animate(styles.inOutBack, style({ transform: '*' }))
],
flyOut: [
style({ transform: '*' }),
animate(styles.inOutBack, style({ transform: 'translateX(-100%)' }))
],
zoomIn: [
style({ transform: 'scale(.5)' }),
animate(styles.inOutBack, style({ transform: '*' }))
],
zoomOut: [
style({ transform: '*' }),
animate(styles.inOutBack, style({ transform: 'scale(.5)' }))
]
}
// 導出動畫時間線定義,供自定義動畫的時候使用
export const animStyle = styles
// 導出動畫
export const fadeIn = [trigger('fadeIn', [transition('void => *', opts.fadeIn)])]
export const fadeOut = [trigger('fadeOut', [transition('* => void', opts.fadeOut)])]
export const stretch = [trigger('stretch', [transition('void => *', opts.stretch)])]
export const shrink = [trigger('shrink', [transition('* => void', opts.shrink)])]
export const flyIn = [trigger('flyIn', [transition('void => *', opts.flyIn)])]
export const flyOut = [trigger('flyOut', [transition('* => void', opts.flyOut)])]
export const zoomIn = [trigger('zoomIn', [transition('void => *', opts.zoomIn)])]
export const zoomOut = [trigger('zoomOut', [transition('* => void', opts.zoomOut)])]
export const simAnim = [
trigger('simAnim', [
transition('* => fadeIn', opts.fadeIn),
transition('* => fadeIn', opts.fadeOut),
transition('* => shrink', opts.shrink),
transition('* => stretch', opts.stretch),
transition('* => flyIn', opts.flyIn),
transition('* => flyOut', opts.flyOut),
transition('* => zoomIn', opts.zoomIn),
transition('* => zoomOut', opts.zoomOut)
])
]
上述代碼定義了8種常用動畫效果,還可以自定義time
變量修改動畫速度。在使用時,可以在組件直接全部引入:
import { simAnim } from './animate.ts';
亦或是單獨引入某個動畫:
import { fadeIn } from './animate.ts';
然后在組件元數據中加入動畫數組:
@Component({
// ...
animations: [simAnim]
})
然后在模板中加入:<div @flyIn @flyOut>...</div>
,也可以寫成<div [@simAnim]="'flyIn'">...</div>
如果上述代碼仍不滿足需求,可以引入其它開源項目,比如:https://github.com/jiayihu/ng-animate
它是一個更強大的開源項目,動畫演示及說明文檔非常詳細,這里就不再贅述。
參考資料
智能推薦
QML進階教程:三、動畫分組(Grouped Animations)
前言: 如果想同時運行幾個動畫并把他們連接起來,或者在一個一個的運行,或者在兩個動畫之間執行一個腳本。動畫分組 提供了很好的幫助,有兩種方法來分組:平行與連續。可以使用SequentialAnimation(連續動畫) 和ParallelAnimation(平行動畫) 來實現它們,它們作為動畫的容器來包含其它的動畫元素。 代碼實例: 運行軌跡:...
[Animations] 快速上手 iOS10 屬性動畫
概述 今天要說的UIViewPropertyAnimator, 是iOS10新的API 詳細 代碼下載:http://www.demodashi.com/demo/10639.html 基礎動畫, 核心動畫到自定義轉場動畫其實都不是什么新東西了, 所以我也是草草看一遍就能夠讀個大概, 但今天要說的UIViewPropertyAnimator, 是iOS10新的API, 其他的好處我還不太清楚, 但...
Animations開源動效分析(一)POP按鈕動畫
最近Github有一個上很火的開源動畫集叫Animations。 我也很喜歡做動畫動效,特來學習觀摩。因為動效的特殊性,很多情況下這個項目里的動效不能直接Copy到我們現有的項目中直接使用,所以搞清楚她們的實現原理就很有必要了。建議配合源碼學習。 POP按鈕動畫 沒用過的POP的請移步Facebook Pop 使用指南 效果如下 思路 整體效果是用三個CAShapeLayer和一個UILabel組...
Animations開源動效分析(二)POP-Stroke動畫
本教程源碼Animations 作者 YouXianMing,建議配合源碼項目食用 Facebook pop動畫框架簡易教程請移步 Facebook Pop 使用指南 CoreAnimation不簡易教程 如果不想看第三條的教程,也要弄明白CALayer的隱式動畫,否則看本文會疑惑,請移步CALayer的隱式動畫和顯式動畫 CAMediaTimingFunction 今天我們來看一下研究一下CAM...
猜你喜歡
freemarker + ItextRender 根據模板生成PDF文件
1. 制作模板 2. 獲取模板,并將所獲取的數據加載生成html文件 2. 生成PDF文件 其中由兩個地方需要注意,都是關于獲取文件路徑的問題,由于項目部署的時候是打包成jar包形式,所以在開發過程中時直接安照傳統的獲取方法沒有一點文件,但是當打包后部署,總是出錯。于是參考網上文章,先將文件讀出來到項目的臨時目錄下,然后再按正常方式加載該臨時文件; 還有一個問題至今沒有解決,就是關于生成PDF文件...
電腦空間不夠了?教你一個小秒招快速清理 Docker 占用的磁盤空間!
Docker 很占用空間,每當我們運行容器、拉取鏡像、部署應用、構建自己的鏡像時,我們的磁盤空間會被大量占用。 如果你也被這個問題所困擾,咱們就一起看一下 Docker 是如何使用磁盤空間的,以及如何回收。 docker 占用的空間可以通過下面的命令查看: TYPE 列出了docker 使用磁盤的 4 種類型: Images:所有鏡像占用的空間,包括拉取下來的鏡像,和本地構建的。 Con...
requests實現全自動PPT模板
http://www.1ppt.com/moban/ 可以免費的下載PPT模板,當然如果要人工一個個下,還是挺麻煩的,我們可以利用requests輕松下載 訪問這個主頁,我們可以看到下面的樣式 點每一個PPT模板的圖片,我們可以進入到詳細的信息頁面,翻到下面,我們可以看到對應的下載地址 點擊這個下載的按鈕,我們便可以下載對應的PPT壓縮包 那我們就開始做吧 首先,查看網頁的源代碼,我們可以看到每一...
Linux C系統編程-線程互斥鎖(四)
互斥鎖 互斥鎖也是屬于線程之間處理同步互斥方式,有上鎖/解鎖兩種狀態。 互斥鎖函數接口 1)初始化互斥鎖 pthread_mutex_init() man 3 pthread_mutex_init (找不到的情況下首先 sudo apt-get install glibc-doc sudo apt-get install manpages-posix-dev) 動態初始化 int pthread_...