How to create Ripple effect on Click - Material Design

后端 未结 10 1557
南旧
南旧 2020-12-12 11:17

I\'m new to CSS animations and I\'ve been trying to make their animation work for the last hours by looking at their code, but I can\'t make it work for now.

I\'m ta

10条回答
  •  甜味超标
    2020-12-12 12:10

    Realization javascript + babel -

    javascript -

    class ImpulseStyleFactory {
        static ANIMATION_DEFAULT_DURATION = 1;
        static ANIMATION_DEFAULT_SIZE = 300;
        static ANIMATION_RATIO = ImpulseStyleFactory.ANIMATION_DEFAULT_DURATION / ImpulseStyleFactory.ANIMATION_DEFAULT_SIZE;
    
        static circleImpulseStyle( x, y, size, color = `#fff`, duration = 1 ){
            return {
                width: `${ size }px`,
                height: `${ size }px`,
    
                background: color,
    
                borderRadius: `50%`,
    
                display: `inline-block`,
    
                pointerEvents: `none`,
    
                position: `absolute`,
    
                top: `${ y - size / 2 }px`,
                left: `${ x - size / 2 }px`,
    
                animation: `impulse ${ duration }s`,
            };
        }
    }
    
    
    class Impulse {
        static service = new Impulse();
    
    
        static install( container ) {
            Impulse.service.containerRegister( container );
        }
        static destroy( container ){
            Impulse.service.containerUnregister( container );
        }
    
        static applyToElement( {x, y}, container ){
            Impulse.service.createImpulse( x, y, container );
        }
    
        constructor(){
            this.impulse_clickHandler = this.impulse_clickHandler.bind(this);
            this.impulse_animationEndHandler = this.impulse_animationEndHandler.bind(this);
    
            this.actives = new Map();
        }
    
        containerRegister( container ){
            container.addEventListener('click', this.impulse_clickHandler);
        }
        containerUnregister( container ){
            container.removeEventListener('click', this.impulse_clickHandler);
        }
    
        createImpulse( x, y, container ){
            let { clientWidth, clientHeight } = container;
    
            let impulse = document.createElement('div');
            impulse.addEventListener('animationend', this.impulse_animationEndHandler);
    
            let size = Math.max( clientWidth, clientHeight ) * 2;
            let color = container.dataset.color;
    
            Object.assign(impulse.style, ImpulseStyleFactory.circleImpulseStyle(
                x, y, size, color
            ));
    
            if( this.actives.has( container ) ){
                this.actives.get( container )
                            .add( impulse );
            }else{
                this.actives.set( container, new Set( [ impulse ] ) );
            }
    
            container.dataset.active = true;
    
            container.appendChild( impulse );
        }
    
    
        impulse_clickHandler({ layerX, layerY, currentTarget: container }){
            this.createImpulse( layerX, layerY, container );        
        }
    
        impulse_animationEndHandler( {currentTarget: impulse} ){
            let { parentNode: container  } = impulse;
    
            this.actives.get( container )
                        .delete( impulse );
    
            if( ! this.actives.get( container ).size ){
                this.actives.delete( container );
    
                container.dataset.active = false;
            }
    
            container.removeChild(impulse);
        }
    }
    

    css -

    @keyframes impulse {
        from {
            opacity: .3;
    
            transform: scale(0);
        }
        to {
            opacity: 0;
    
            transform: scale(1);
        }
    }
    

    to use so -

    html -

    javascript -

    let impulses = document.querySelectorAll('.impulse');
    let impulseAll = Array.from( impulses );
    
    impulseAll.forEach( Impulse.install );
    

    Life example Impulse.install ( impulse create in coords of click, add handler event click ) -

    class ImpulseStyleFactory {
        static ANIMATION_DEFAULT_DURATION = 1;
        static ANIMATION_DEFAULT_SIZE = 300;
        static ANIMATION_RATIO = ImpulseStyleFactory.ANIMATION_DEFAULT_DURATION / ImpulseStyleFactory.ANIMATION_DEFAULT_SIZE;
    
        static circleImpulseStyle( x, y, size, color = `#fff`, duration = 1 ){
            return {
                width: `${ size }px`,
                height: `${ size }px`,
    
                background: color,
    
                borderRadius: `50%`,
    
                display: `inline-block`,
    
                pointerEvents: `none`,
    
                position: `absolute`,
    
                top: `${ y - size / 2 }px`,
                left: `${ x - size / 2 }px`,
    
                animation: `impulse ${ duration }s`,
            };
        }
    }
    
    
    class Impulse {
        static service = new Impulse();
    
    
        static install( container ) {
            Impulse.service.containerRegister( container );
        }
        static destroy( container ){
            Impulse.service.containerUnregister( container );
        }
    
        static applyToElement( {x, y}, container ){
            Impulse.service.createImpulse( x, y, container );
        }
    
        constructor(){
            this.impulse_clickHandler = this.impulse_clickHandler.bind(this);
            this.impulse_animationEndHandler = this.impulse_animationEndHandler.bind(this);
    
            this.actives = new Map();
        }
    
        containerRegister( container ){
            container.addEventListener('click', this.impulse_clickHandler);
        }
        containerUnregister( container ){
            container.removeEventListener('click', this.impulse_clickHandler);
        }
    
        createImpulse( x, y, container ){
            let { clientWidth, clientHeight } = container;
    
            let impulse = document.createElement('div');
            impulse.addEventListener('animationend', this.impulse_animationEndHandler);
    
            let size = Math.max( clientWidth, clientHeight ) * 2;
            let color = container.dataset.color;
    
            Object.assign(impulse.style, ImpulseStyleFactory.circleImpulseStyle(
                x, y, size, color
            ));
    
            if( this.actives.has( container ) ){
                this.actives.get( container )
                    .add( impulse );
            }else{
                this.actives.set( container, new Set( [ impulse ] ) );
            }
    
            container.dataset.active = true;
    
            container.appendChild( impulse );
        }
    
    
        impulse_clickHandler({ layerX, layerY, currentTarget: container }){
            this.createImpulse( layerX, layerY, container );
        }
    
        impulse_animationEndHandler( {currentTarget: impulse} ){
            let { parentNode: container  } = impulse;
    
            this.actives.get( container )
                .delete( impulse );
    
            if( ! this.actives.get( container ).size ){
                this.actives.delete( container );
    
                container.dataset.active = false;
            }
    
            container.removeChild(impulse);
        }
    }
    
    
    
    let impulses = document.querySelectorAll('.impulse');
    let impulseAll = Array.from( impulses );
    
    impulseAll.forEach( Impulse.install );
    @import "https://cdnjs.cloudflare.com/ajax/libs/normalize/6.0.0/normalize.min.css";
    /*@import url('https://fonts.googleapis.com/css?family=Roboto+Mono');*/
    
    * {
        box-sizing: border-box;
    }
    
    html {
        font-family: 'Roboto Mono', monospace;
    }
    
    body {
        width: 100%;
        height: 100%;
    
        margin: 0;
    
        position: absolute;
    
    
    }
    
    main {
        width: 100%;
        height: 100%;
    
        overflow: hidden;
    
        position: relative;
    }
    
    
    .container {
        position: absolute;
    
        top: 0;
        left: 0;
    }
    
    .centred {
        display: flex;
    
        justify-content: center;
    
        align-items: center;
    }
    
    .shadow-xs {
        box-shadow: rgba(0, 0, 0, 0.117647) 0px 1px 6px, rgba(0, 0, 0, 0.117647) 0px 1px 4px;
    }
    .sample-impulse {
        transition: all .5s;
    
        overflow: hidden;
    
        position: relative;
    }
    .sample-impulse[data-active="true"] {
        box-shadow: rgba(0, 0, 0, 0.156863) 0px 3px 10px, rgba(0, 0, 0, 0.227451) 0px 3px 10px;
    }
    
    
    
    .panel {
        width: 300px;
        height: 100px;
    
        background: #fff;
    }
    
    
    .panel__hidden-label {
        color: #fff;
    
        font-size: 2rem;
        font-weight: bold;
    
        pointer-events: none;
    
        z-index: 1;
    
        position: absolute;
    }
    .panel__default-label {
        pointer-events: none;
    
        z-index: 2;
    
        position: absolute;
    }
    
    .sample-impulse[data-active="true"] .panel__default-label {
        display: none;
    }
    
    
    
    @keyframes impulse {
        from {
            opacity: .3;
    
            transform: scale(0);
        }
        to {
            opacity: 0;
    
            transform: scale(1);
        }
    }
    StackOverflow click me

    Life example Impulse.applyToElement ( impulse coords setby user, not add handler event click ) -

    class ImpulseStyleFactory {
        static ANIMATION_DEFAULT_DURATION = 1;
        static ANIMATION_DEFAULT_SIZE = 300;
        static ANIMATION_RATIO = ImpulseStyleFactory.ANIMATION_DEFAULT_DURATION / ImpulseStyleFactory.ANIMATION_DEFAULT_SIZE;
    
        static circleImpulseStyle( x, y, size, color = `#fff`, duration = 1 ){
            return {
                width: `${ size }px`,
                height: `${ size }px`,
    
                background: color,
    
                borderRadius: `50%`,
    
                display: `inline-block`,
    
                pointerEvents: `none`,
    
                position: `absolute`,
    
                top: `${ y - size / 2 }px`,
                left: `${ x - size / 2 }px`,
    
                animation: `impulse ${ duration }s`,
            };
        }
    }
    
    
    class Impulse {
        static service = new Impulse();
    
    
        static install( container ) {
            Impulse.service.containerRegister( container );
        }
        static destroy( container ){
            Impulse.service.containerUnregister( container );
        }
    
        static applyToElement( {x, y}, container ){
            Impulse.service.createImpulse( x, y, container );
        }
    
        constructor(){
            this.impulse_clickHandler = this.impulse_clickHandler.bind(this);
            this.impulse_animationEndHandler = this.impulse_animationEndHandler.bind(this);
    
            this.actives = new Map();
        }
    
        containerRegister( container ){
            container.addEventListener('click', this.impulse_clickHandler);
        }
        containerUnregister( container ){
            container.removeEventListener('click', this.impulse_clickHandler);
        }
    
        createImpulse( x, y, container ){
            let { clientWidth, clientHeight } = container;
    
            let impulse = document.createElement('div');
            impulse.addEventListener('animationend', this.impulse_animationEndHandler);
    
            let size = Math.max( clientWidth, clientHeight ) * 2;
            let color = container.dataset.color;
    
            Object.assign(impulse.style, ImpulseStyleFactory.circleImpulseStyle(
                x, y, size, color
            ));
    
            if( this.actives.has( container ) ){
                this.actives.get( container )
                    .add( impulse );
            }else{
                this.actives.set( container, new Set( [ impulse ] ) );
            }
    
            container.dataset.active = true;
    
            container.appendChild( impulse );
        }
    
    
        impulse_clickHandler({ layerX, layerY, currentTarget: container }){
            this.createImpulse( layerX, layerY, container );
        }
    
        impulse_animationEndHandler( {currentTarget: impulse} ){
            let { parentNode: container  } = impulse;
    
            this.actives.get( container )
                .delete( impulse );
    
            if( ! this.actives.get( container ).size ){
                this.actives.delete( container );
    
                container.dataset.active = false;
            }
    
            container.removeChild(impulse);
        }
    }
    
    
    
    const generateRandomPointByRectdAll = ( { width, height }, length = 1 ) => {
        let result = [];
    
        while( length-- ){
            result.push( {
                x: Math.round( Math.random() * width ),
                y: Math.round( Math.random() * height )
            } );
        }
    
        return result;
    };
    
    const delayTask = ( task, delay ) => new Promise( ( resolve, reject ) => {
        let timeoutID = setTimeout( () => task( ), delay )
    } );
    
    document.addEventListener( 'click', () => {
        const MAX_IMPULSE_DELAY_TIME = 5000;
    
        let container = document.querySelector('.custom-impulse');
        let pointAll = generateRandomPointByRectdAll( {
            width: container.clientWidth,
            height: container.clientHeight
        }, 5 );
        let taskAll = pointAll.map( point => () => Impulse.applyToElement( point, container ) );
        let delayTaskAll = taskAll.map( task => delayTask( task, Math.round( Math.random() * MAX_IMPULSE_DELAY_TIME ) ) );
    } );
    @import "https://cdnjs.cloudflare.com/ajax/libs/normalize/6.0.0/normalize.min.css";
    /*@import url('https://fonts.googleapis.com/css?family=Roboto+Mono');*/
    
    * {
        box-sizing: border-box;
    }
    
    html {
        font-family: 'Roboto Mono', monospace;
    }
    
    body {
        width: 100%;
        height: 100%;
    
        margin: 0;
    
        position: absolute;
    
    
    }
    
    main {
        width: 100%;
        height: 100%;
    
        overflow: hidden;
    
        position: relative;
    }
    
    .container-fill {
        width: 100%;
        height: 100%;
    }
    
    .container {
        position: absolute;
    
        top: 0;
        left: 0;
    }
    
    .centred {
        display: flex;
    
        justify-content: center;
    
        align-items: center;
    }
    
    
    .custom-impulse {
        will-change: transform, opasity;
    
        position: absolute;
    }
    
    
    @keyframes impulse {
        from {
            opacity: .3;
    
            transform: scale(0);
        }
        to {
            opacity: 0;
    
            transform: scale(1);
        }
    }
    click me

提交回复
热议问题