mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-20 12:29:55 +08:00
perf(ripple): md ripple effect update to not affect layout
This commit is contained in:

committed by
Adam Bradley

parent
156223edba
commit
14a3ea2ef8
@ -423,6 +423,8 @@ $button-md-fab-box-shadow-activated: 0 5px 15px 0 rgba(0, 0, 0, .4),
|
|||||||
|
|
||||||
.button-effect {
|
.button-effect {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
display: none;
|
display: none;
|
||||||
|
|
||||||
@ -431,6 +433,7 @@ $button-md-fab-box-shadow-activated: 0 5px 15px 0 rgba(0, 0, 0, .4),
|
|||||||
background-color: $button-md-ripple-background-color;
|
background-color: $button-md-ripple-background-color;
|
||||||
opacity: .2;
|
opacity: .2;
|
||||||
|
|
||||||
|
transform-origin: center center;
|
||||||
transition-timing-function: ease-in-out;
|
transition-timing-function: ease-in-out;
|
||||||
|
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Activator } from './activator';
|
import { Activator } from './activator';
|
||||||
import { App } from '../app/app';
|
import { App } from '../app/app';
|
||||||
import { PointerCoordinates, CSS, hasPointerMoved, nativeRaf, pointerCoord, rafFrames } from '../../util/dom';
|
import { PointerCoordinates, CSS, hasPointerMoved, pointerCoord, rafFrames } from '../../util/dom';
|
||||||
import { Config } from '../../config/config';
|
import { Config } from '../../config/config';
|
||||||
|
|
||||||
|
|
||||||
@ -14,33 +14,25 @@ export class RippleActivator extends Activator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
downAction(ev: UIEvent, activatableEle: HTMLElement, startCoord: PointerCoordinates) {
|
downAction(ev: UIEvent, activatableEle: HTMLElement, startCoord: PointerCoordinates) {
|
||||||
let self = this;
|
if (this.disableActivated(ev)) {
|
||||||
if (self.disableActivated(ev)) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// queue to have this element activated
|
// queue to have this element activated
|
||||||
self._queue.push(activatableEle);
|
this._queue.push(activatableEle);
|
||||||
|
|
||||||
nativeRaf(function() {
|
for (var i = 0; i < this._queue.length; i++) {
|
||||||
for (var i = 0; i < self._queue.length; i++) {
|
var queuedEle = this._queue[i];
|
||||||
var queuedEle = self._queue[i];
|
|
||||||
if (queuedEle && queuedEle.parentNode) {
|
if (queuedEle && queuedEle.parentNode) {
|
||||||
self._active.push(queuedEle);
|
this._active.push(queuedEle);
|
||||||
|
|
||||||
// DOM WRITE
|
// DOM WRITE
|
||||||
queuedEle.classList.add(self._css);
|
queuedEle.classList.add(this._css);
|
||||||
|
|
||||||
var j = queuedEle.childElementCount;
|
var j = queuedEle.childElementCount;
|
||||||
while (j--) {
|
while (j--) {
|
||||||
var rippleEle: any = queuedEle.children[j];
|
var rippleEle: any = queuedEle.children[j];
|
||||||
if (rippleEle.classList.contains('button-effect')) {
|
if (rippleEle.classList.contains('button-effect')) {
|
||||||
// DOM WRITE
|
|
||||||
rippleEle.style.left = '-9999px';
|
|
||||||
rippleEle.style.opacity = '';
|
|
||||||
rippleEle.style[CSS.transform] = 'scale(0.001) translateZ(0px)';
|
|
||||||
rippleEle.style[CSS.transition] = '';
|
|
||||||
|
|
||||||
// DOM READ
|
// DOM READ
|
||||||
var clientRect = activatableEle.getBoundingClientRect();
|
var clientRect = activatableEle.getBoundingClientRect();
|
||||||
rippleEle.$top = clientRect.top;
|
rippleEle.$top = clientRect.top;
|
||||||
@ -52,64 +44,77 @@ export class RippleActivator extends Activator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self._queue = [];
|
this._queue = [];
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
upAction(ev: UIEvent, activatableEle: HTMLElement, startCoord: PointerCoordinates) {
|
upAction(ev: UIEvent, activatableEle: HTMLElement, startCoord: PointerCoordinates) {
|
||||||
if (!hasPointerMoved(6, startCoord, pointerCoord(ev))) {
|
if (hasPointerMoved(6, startCoord, pointerCoord(ev))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let i = activatableEle.childElementCount;
|
let i = activatableEle.childElementCount;
|
||||||
|
|
||||||
while (i--) {
|
while (i--) {
|
||||||
var rippleEle: any = activatableEle.children[i];
|
var rippleEle: any = activatableEle.children[i];
|
||||||
if (rippleEle.classList.contains('button-effect')) {
|
if (rippleEle.classList.contains('button-effect')) {
|
||||||
var clientPointerX = (startCoord.x - rippleEle.$left);
|
this.startRippleEffect(rippleEle, activatableEle, startCoord);
|
||||||
var clientPointerY = (startCoord.y - rippleEle.$top);
|
break;
|
||||||
|
|
||||||
var x = Math.max(Math.abs(rippleEle.$width - clientPointerX), clientPointerX) * 2;
|
|
||||||
var y = Math.max(Math.abs(rippleEle.$height - clientPointerY), clientPointerY) * 2;
|
|
||||||
var diameter = Math.min(Math.max(Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)), 64), 240);
|
|
||||||
|
|
||||||
if (activatableEle.hasAttribute('ion-item')) {
|
|
||||||
diameter = Math.min(diameter, 140);
|
|
||||||
}
|
|
||||||
|
|
||||||
var radius = Math.sqrt(rippleEle.$width + rippleEle.$height);
|
|
||||||
|
|
||||||
var scaleTransitionDuration = Math.max(1600 * Math.sqrt(radius / TOUCH_DOWN_ACCEL) + 0.5, 260);
|
|
||||||
var opacityTransitionDuration = scaleTransitionDuration * 0.7;
|
|
||||||
var opacityTransitionDelay = scaleTransitionDuration - opacityTransitionDuration;
|
|
||||||
|
|
||||||
// DOM WRITE
|
|
||||||
rippleEle.style.width = rippleEle.style.height = diameter + 'px';
|
|
||||||
rippleEle.style.marginTop = rippleEle.style.marginLeft = -(diameter / 2) + 'px';
|
|
||||||
rippleEle.style.left = clientPointerX + 'px';
|
|
||||||
rippleEle.style.top = clientPointerY + 'px';
|
|
||||||
rippleEle.style.opacity = '0';
|
|
||||||
rippleEle.style[CSS.transform] = 'scale(1) translateZ(0px)';
|
|
||||||
rippleEle.style[CSS.transition] = 'transform ' +
|
|
||||||
scaleTransitionDuration +
|
|
||||||
'ms,opacity ' +
|
|
||||||
opacityTransitionDuration +
|
|
||||||
'ms ' +
|
|
||||||
opacityTransitionDelay + 'ms';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
super.upAction(ev, activatableEle, startCoord);
|
super.upAction(ev, activatableEle, startCoord);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
startRippleEffect(rippleEle: any, activatableEle: HTMLElement, startCoord: PointerCoordinates) {
|
||||||
|
let clientPointerX = (startCoord.x - rippleEle.$left);
|
||||||
|
let clientPointerY = (startCoord.y - rippleEle.$top);
|
||||||
|
|
||||||
|
let x = Math.max(Math.abs(rippleEle.$width - clientPointerX), clientPointerX) * 2;
|
||||||
|
let y = Math.max(Math.abs(rippleEle.$height - clientPointerY), clientPointerY) * 2;
|
||||||
|
let diameter = Math.min(Math.max(Math.hypot(x, y), 64), 240);
|
||||||
|
|
||||||
|
if (activatableEle.hasAttribute('ion-item')) {
|
||||||
|
diameter = Math.min(diameter, 140);
|
||||||
|
}
|
||||||
|
|
||||||
|
clientPointerX -= diameter / 2;
|
||||||
|
clientPointerY -= diameter / 2;
|
||||||
|
|
||||||
|
clientPointerX = Math.round(clientPointerX);
|
||||||
|
clientPointerY = Math.round(clientPointerY);
|
||||||
|
diameter = Math.round(diameter);
|
||||||
|
|
||||||
|
// Reset ripple
|
||||||
|
rippleEle.style.opacity = '';
|
||||||
|
rippleEle.style[CSS.transform] = `translate3d(${clientPointerX}px, ${clientPointerY}px, 0px) scale(0.001)`;
|
||||||
|
rippleEle.style[CSS.transition] = '';
|
||||||
|
|
||||||
|
// Start ripple animation
|
||||||
|
let radius = Math.sqrt(rippleEle.$width + rippleEle.$height);
|
||||||
|
let scaleTransitionDuration = Math.max(1600 * Math.sqrt(radius / TOUCH_DOWN_ACCEL) + 0.5, 260);
|
||||||
|
let opacityTransitionDuration = Math.round(scaleTransitionDuration * 0.7);
|
||||||
|
let opacityTransitionDelay = Math.round(scaleTransitionDuration - opacityTransitionDuration);
|
||||||
|
scaleTransitionDuration = Math.round(scaleTransitionDuration);
|
||||||
|
|
||||||
|
let transform = `translate3d(${clientPointerX}px, ${clientPointerY}px, 0px) scale(1)`;
|
||||||
|
let transition = `transform ${scaleTransitionDuration}ms,opacity ${opacityTransitionDuration}ms ${opacityTransitionDelay}ms`;
|
||||||
|
|
||||||
|
rafFrames(2, () => {
|
||||||
|
// DOM WRITE
|
||||||
|
rippleEle.style.width = rippleEle.style.height = diameter + 'px';
|
||||||
|
rippleEle.style.opacity = '0';
|
||||||
|
rippleEle.style[CSS.transform] = transform;
|
||||||
|
rippleEle.style[CSS.transition] = transition;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
deactivate() {
|
deactivate() {
|
||||||
// remove the active class from all active elements
|
// remove the active class from all active elements
|
||||||
let self = this;
|
this._queue = [];
|
||||||
self._queue = [];
|
|
||||||
|
|
||||||
rafFrames(2, function() {
|
rafFrames(2, () => {
|
||||||
for (var i = 0; i < self._active.length; i++) {
|
for (var i = 0; i < this._active.length; i++) {
|
||||||
self._active[i].classList.remove(self._css);
|
this._active[i].classList.remove(this._css);
|
||||||
}
|
}
|
||||||
self._active = [];
|
this._active = [];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user