mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-18 19:21:34 +08:00
268 lines
5.6 KiB
JavaScript
268 lines
5.6 KiB
JavaScript
import * as util from 'ionic/util/util';
|
|
|
|
|
|
export class Animation {
|
|
|
|
constructor(el) {
|
|
this._el = [];
|
|
this._parent = null;
|
|
this._children = [];
|
|
this._players = [];
|
|
|
|
this._from = null;
|
|
this._to = null;
|
|
this._duration = null;
|
|
this._easing = null;
|
|
|
|
this._beforeAddCls = [];
|
|
this._beforeRmvCls = [];
|
|
this._afterAddCls = [];
|
|
this._afterRmvCls = [];
|
|
|
|
this.elements(el);
|
|
}
|
|
|
|
elements(el) {
|
|
if (el) {
|
|
if (typeof el === 'string') {
|
|
el = document.querySelectorAll(ele);
|
|
}
|
|
|
|
if (el.length) {
|
|
for (let i = 0; i < el.length; i++) {
|
|
this._el.push(el[i]);
|
|
}
|
|
|
|
} else if (el.nodeType) {
|
|
this._el.push(el);
|
|
}
|
|
}
|
|
return this;
|
|
}
|
|
|
|
parent(parentAnimation) {
|
|
this._parent = parentAnimation;
|
|
return this;
|
|
}
|
|
|
|
addChild(childAnimation) {
|
|
if (childAnimation) {
|
|
childAnimation.parent(this);
|
|
this._children.push(childAnimation);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
children(arr) {
|
|
arr = Array.isArray(arr) ? arr : arguments;
|
|
for (let i = 0; i < arr.length; i++) {
|
|
this.addChild(arr[i]);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
duration(value) {
|
|
if (arguments.length) {
|
|
this._duration = value;
|
|
return this;
|
|
}
|
|
return this._duration || (this._parent && this._parent.duration());
|
|
}
|
|
|
|
easing(value) {
|
|
if (arguments.length) {
|
|
this._easing = value;
|
|
return this;
|
|
}
|
|
return this._easing || (this._parent && this._parent.easing());
|
|
}
|
|
|
|
from(property, value) {
|
|
if (!this._from) {
|
|
this._from = {};
|
|
}
|
|
this._from[property] = value;
|
|
return this;
|
|
}
|
|
|
|
to(property, value) {
|
|
if (!this._to) {
|
|
this._to = {};
|
|
}
|
|
this._to[property] = value;
|
|
return this;
|
|
}
|
|
|
|
get beforePlay() {
|
|
return {
|
|
addClass: (className) => {
|
|
this._beforeAddCls.push(className);
|
|
return this;
|
|
},
|
|
removeClass: (className) => {
|
|
this._beforeRmvCls.push(className);
|
|
return this;
|
|
}
|
|
}
|
|
}
|
|
|
|
get afterFinish() {
|
|
return {
|
|
addClass: (className) => {
|
|
this._afterAddCls.push(className);
|
|
return this;
|
|
},
|
|
removeClass: (className) => {
|
|
this._afterRmvCls.push(className);
|
|
return this;
|
|
}
|
|
}
|
|
}
|
|
|
|
play() {
|
|
let promises = [];
|
|
|
|
for (let i = 0; i < this._children.length; i++) {
|
|
promises.push( this._children[i].play() );
|
|
}
|
|
|
|
if (!this._to) {
|
|
// probably just add/removing classes, create bogus transition
|
|
this._from = this._to = {'opacity': 1};
|
|
}
|
|
|
|
if (!this._players.length) {
|
|
for (let i = 0; i < this._el.length; i++) {
|
|
var ele = this._el[i];
|
|
|
|
for (let j = 0; j < this._beforeAddCls.length; j++) {
|
|
ele.classList.add(this._beforeAddCls[j]);
|
|
}
|
|
|
|
for (let j = 0; j < this._beforeRmvCls.length; j++) {
|
|
ele.classList.remove(this._beforeRmvCls[j]);
|
|
}
|
|
|
|
var player = new Animate(ele, this._from, this._to, this.duration(), this.easing());
|
|
this._players.push(player);
|
|
|
|
promises.push(player.promise);
|
|
}
|
|
|
|
} else {
|
|
for (let i = 0; i < this._players.length; i++) {
|
|
this._players[i].play();
|
|
}
|
|
}
|
|
|
|
var promise = Promise.all(promises);
|
|
|
|
promise.then(() => {
|
|
for (let i = 0; i < this._el.length; i++) {
|
|
var ele = this._el[i];
|
|
|
|
for (let j = 0; j < this._afterAddCls.length; j++) {
|
|
ele.classList.add(this._afterAddCls[j]);
|
|
}
|
|
|
|
for (let j = 0; j < this._afterRmvCls.length; j++) {
|
|
ele.classList.remove(this._afterRmvCls[j]);
|
|
}
|
|
}
|
|
});
|
|
|
|
return promise;
|
|
}
|
|
|
|
pause() {
|
|
for (let i = 0; i < this._children.length; i++) {
|
|
this._children[i].pause();
|
|
}
|
|
|
|
for (let i = 0; i < this._players.length; i++) {
|
|
this._players[i].pause();
|
|
}
|
|
}
|
|
|
|
progress(value) {
|
|
for (let i = 0; i < this._children.length; i++) {
|
|
this._children[i].progress(value);
|
|
}
|
|
|
|
if (!this._players.length) {
|
|
this.play();
|
|
this.pause();
|
|
}
|
|
|
|
for (let i = 0; i < this._players.length; i++) {
|
|
this._players[i].progress(value);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
class Animate {
|
|
|
|
constructor(ele, fromEffect, toEffect, duration, easing) {
|
|
// https://w3c.github.io/web-animations/
|
|
// not using the direct API methods because they're still in flux
|
|
// however, element.animate() seems locked in and uses the latest
|
|
// and correct API methods under the hood, so really doesn't matter
|
|
|
|
// fromEffect must be manually computed if it wasn't provided
|
|
// https://github.com/web-animations/web-animations-js/issues/14
|
|
fromEffect = fromEffect || {};
|
|
let style = null;
|
|
for (let prop in toEffect) {
|
|
if (util.isBlank(fromEffect[prop])) {
|
|
style = style || window.getComputedStyle(ele);
|
|
fromEffect[prop] = style[prop];
|
|
}
|
|
}
|
|
|
|
this._duration = duration;
|
|
this._easing = easing;
|
|
|
|
this.player = ele.animate([fromEffect, toEffect], {
|
|
duration: duration,
|
|
easing: easing,
|
|
fill: 'both'
|
|
});
|
|
|
|
this.promise = new Promise(resolve => {
|
|
this.player.onfinish = () => {
|
|
resolve();
|
|
};
|
|
});
|
|
|
|
}
|
|
|
|
play() {
|
|
this.player.play();
|
|
}
|
|
|
|
pause() {
|
|
this.player.pause();
|
|
}
|
|
|
|
progress(value) {
|
|
let player = this.player;
|
|
|
|
// passed a number between 0 and 1
|
|
value = Math.max(0, Math.min(1, parseFloat(value)));
|
|
|
|
if (value === 1) {
|
|
player.currentTime = (this._duration * 0.9999);
|
|
player.play();
|
|
return;
|
|
}
|
|
|
|
if (player.playState !== 'paused') {
|
|
player.pause();
|
|
}
|
|
|
|
player.currentTime = (this._duration * value);
|
|
}
|
|
|
|
}
|