8
\$\begingroup\$

I have "translated" this example built with jQuery in vanilla JavaScript, but I'd like to know if there are better ways to do it.

The jQuery version uses offset() function and on() for every events, while I've used this function for offset:

function offset(elt) {
    var rect = elt.getBoundingClientRect(), bodyElt = document.body;
    return {
        top: rect.top + bodyElt .scrollTop,
        left: rect.left + bodyElt .scrollLeft
    }
}

and this one to prefix AnimationEnd event :

var pfx = ["webkit", "moz", "MS", "o", ""];
function prefixedEvent(element, type, callback) {
    for (var p = 0; p < pfx.length; p++) {
        if (!pfx[p]) type = type.toLowerCase();
        element.addEventListener(pfx[p]+type, callback, false);
    }
}

From this sitepoint article

My entire code is visible here at Codepen.

Otherwise, here is my example code:

HTML

<button>
  <span class="ripples">
    <span class="ripples-circle"></span>
  </span>Test
</button>
<button>
  <span class="ripples">
    <span class="ripples-circle"></span>
  </span>Test
</button>
<button>
  <span class="ripples">
    <span class="ripples-circle"></span>
  </span>Test
</button>

SCSS (without prefixes):

button {
    height: 100px;
    width: 100px;
    background-color: gray;
    border-style:solid;
    color: #fff;
    position: relative;
    display: inline-block;
    padding: 12px 24px;
    margin-top: 0;
    margin-bottom: 0;
    vertical-align: middle;
    transition: all .25s ease;

    &:focus {
        outline: 0;
    }

    &:hover {
        background-color: darken(gray, 5%);
    }
    }

    .ripples {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        overflow: hidden;
        background-color: transparent;

    &.is-active {
        .ripples-circle {
            animation: ripples .4s ease-in;
        }
    }

    .ripples-circle {
        background-color: rgba(255,255,255,.5);
        position: absolute;
        top: 50%;
        left: 50%;
        opacity: 0;
        width: 0;
        height: 0;
        border-radius: 50%;
        transform: translate(-50%, -50%);
    }
}

@keyframes ripples {
    0% {
        opacity: 0;
    }
    25% {
        opacity: 1;
    }
    100% {
        width: 200%;
        padding-bottom: 200%;
        opacity: 0;
    }
}

JavaScript:

(function(window, document, undefined){
    'use strict';
    //http://www.debray-jerome.fr/js-performance-la-fonction-offset-de-jquery-vs-vanilla-javascript-23.html
    function offset(elt) {
        var rect = elt.getBoundingClientRect(), bodyElt = document.body;
        return {
            top: rect.top + bodyElt .scrollTop,
            left: rect.left + bodyElt .scrollLeft
        }
    }

  //http://www.sitepoint.com/css3-animation-javascript-event-handlers/

    var pfx = ["webkit", "moz", "MS", "o", ""];
    function prefixedEvent(element, type, callback) {
        for (var p = 0; p < pfx.length; p++) {
            if (!pfx[p]) type = type.toLowerCase();
            element.addEventListener(pfx[p]+type, callback, false);
        }
    }

    var ripples = document.querySelectorAll('.ripples');
    for(var i=0; i < ripples.length;i++ ){
         ripples[i].addEventListener('click', function(e){
            var rippleThis = this;
            var parentOffset = offset(rippleThis.parentNode);
            var x = e.pageX - parentOffset.left;
            var y = e.pageY + parentOffset.top;
            var j;
            var childrenLength = rippleThis.childNodes.length;
            var targetChild;
            for(j = 0; j < childrenLength; j++){
              if(rippleThis.childNodes[j].className == 'ripples-circle') targetChild = rippleThis.childNodes[j];
            }

            targetChild.style.top = y + 'px';
            targetChild.style.left = x + 'px';

            rippleThis.className = 'ripples is-active';
        }, false);
        prefixedEvent(ripples[i], "AnimationEnd", function(e){
            e.currentTarget.className = 'ripples';
        });
    }

})(window, document);
\$\endgroup\$
0
3
\$\begingroup\$

Some things that I would do differently in this for loop

for(var i=0; i < ripples.length;i++ ){
     ripples[i].addEventListener('click', function(e){
        var rippleThis = this;
        var parentOffset = offset(rippleThis.parentNode);
        var x = e.pageX - parentOffset.left;
        var y = e.pageY + parentOffset.top;
        var j;
        var childrenLength = rippleThis.childNodes.length;
        var targetChild;
        for(j = 0; j < childrenLength; j++){
          if(rippleThis.childNodes[j].className == 'ripples-circle') targetChild = rippleThis.childNodes[j];
        }

        targetChild.style.top = y + 'px';
        targetChild.style.left = x + 'px';

        rippleThis.className = 'ripples is-active';
    }, false);
    prefixedEvent(ripples[i], "AnimationEnd", function(e){
        e.currentTarget.className = 'ripples';
    });
}

First thing I saw was that you created an increment variable outside of the for loop declaration, that just makes things a little messy, there isn't any reason for var j; outside of the for loop.

rippleThis isn't a good variable name, I would name this variable thisRipple because it is literally this ripple object.

You should also give your code some breathing room, like in the for loop declaration

var i = 0; i < ripples.length; i++ looks better than var i=0; i < ripples.length;i++

After all these changes it would look like this

for(var i = 0; i < ripples.length; i++ ){
    ripples[i].addEventListener('click', function(e){
        var thisRipple = this;
        var parentOffset = offset(thisRipple.parentNode);
        var x = e.pageX - parentOffset.left;
        var y = e.pageY + parentOffset.top;
        var childrenLength = thisRipple.childNodes.length;
        var targetChild;
        for(var j = 0; j < childrenLength; j++){
            if(thisRipple.childNodes[j].className == 'ripples-circle') targetChild = thisRipple.childNodes[j];
        }

        targetChild.style.top = y + 'px';
        targetChild.style.left = x + 'px';

        thisRipple.className = 'ripples is-active';
    }, false);
    prefixedEvent(ripples[i], "AnimationEnd", function(e){
        e.currentTarget.className = 'ripples';
    });
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.