v-ripple
HTML
<div id="app">
<div v-ripple class="target">
</div>
<div v-ripple.pink class="target">
</div>
<div v-ripple.small.slow class="target">
</div>
<div v-ripple.slow.white class="target">
</div>
</div>
CSS
.target {
margin-top: 20px;
margin-left: 100px;
height: 100px;
width: 100px;
position: relative;
background-color: #777;
}
.has-ripple {
overflow: hidden;
user-select: none;
}
.point {
position: absolute;
background-color: #000;
transition: all 0.5s;
width: 2px;
height: 2px;
border-radius: 999px;
overflow: hidden;
}
.ripple-effect {
animation: ripple-animation 0.4s;
}
.ripple-effect.slow {
animation: ripple-animation 0.9s;
}
.ripple-effect-small {
animation: ripple-animation-small 0.2s;
}
.ripple-effect-small.slow {
animation: ripple-animation-small 0.7s;
}
@keyframes ripple-animation {
from {
transform: scale(1);
opacity: 0.4;
}
to {
transform: scale(100);
opacity: 0;
}
}
@keyframes ripple-animation-small {
from {
transform: scale(1);
opacity: 0.4;
}
to {
transform: scale(30);
opacity: 0;
}
}
Babel + JSX
Vue.directive('ripple', {
bind () {
this.handler = e => {
this.el.classList.add('has-ripple')
const width = parseInt(window.getComputedStyle(this.el,null).getPropertyValue('width').slice(0, -2))
const height = parseInt(window.getComputedStyle(this.el,null).getPropertyValue('height').slice(0, -2))
const rect = this.el.getBoundingClientRect()
const x = e.pageX - (rect.left + document.body.scrollLeft)
const y = e.pageY - (rect.top + document.body.scrollTop)
let point = document.createElement('span')
point.classList.add('point')
if (this.modifiers.white) {
point.style['background-color'] = '#fff'
} else {
point.style['background-color'] = this.vm.$options.ripple.color
}
point.style.top = `${y}px`
point.style.left = `${x}px`
this.el.appendChild(point)
// 2. expand effect on point
if (this.modifiers.small) {
point.classList.add('ripple-effect-small')
} else {
point.classList.add('ripple-effect')
}
if (this.modifiers.slow) {
point.classList.add('slow')
}
// 3. remove ugly point
point.addEventListener('animationend', function (e) {
point.parentNode.removeChild(point)
})
}
this.el.addEventListener('click', this.handler)
},
update (newValue, oldValue) {
},
unbind () {
this.el.removeEventListener('click', this.handler)
}
})
new Vue({
el: '#app',
ripple: {
color: '#f18c16'
}
})