Fancy Exploding Button
본문
https://codepen.io/takaneichinose/pen/jONdGxM
HTML :
<div id="app">
<ti-button-splatter text="PRESS ME"></ti-button-splatter>
</div>
CSS :
@import url("https://fonts.googleapis.com/css?family=Open+Sans:400,400i,700");
html, body {
width: 100%;
height: 100%;
}
#app {
font-family: 'Open Sans', sans-serif;
font-size: 24px;
background-image: linear-gradient(to bottom right,
#ff4e4e 0 15%, #f8ff64 40% 60%, #00ce1a 85% 100%);
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.btn-splatter {
color: #ffffff;
font-family: inherit;
font-weight: bold;
background-color: #4487ed;
width: 12em;
height: 4em;
border: 0;
outline: 0;
padding: 0;
margin: 0;
position: relative;
border-radius: 0.9em;
box-shadow: 0 0.6em 0.9em rgba(0, 0, 0, 0.6);
user-select: none; /* Thanks to @SplittyDev */
transform: translateY(-0.5em);
transition:
background-color 300ms cubic-bezier(0.18, 0.89, 0.32, 1.28),
box-shadow 300ms cubic-bezier(0.18, 0.89, 0.32, 1.28),
transform 300ms cubic-bezier(0.18, 0.89, 0.32, 1.28);
}
.btn-splatter:focus {
outline: 0;
}
.btn-splatter:active {
background-color: #2770df;
box-shadow: 0 0 0 rgba(0, 0, 0, 0.5);
transform: translateY(0em) scale(0.9);
transition:
background-color 150ms ease-out,
box-shadow 150ms ease-out,
transform 150ms ease-out;
}
.splatter {
position: absolute;
top: 0;
left: 0;
}
.splatter-round, .splatter-ring, .splatter-star {
position: absolute;
}
.splatter-round {
width: 1em;
height: 1em;
background-color: #1da5ff;
border-radius: 50%;
}
.splatter-ring {
width: 0.8em;
height: 0.8em;
border: solid 0.35em #0099e6;
border-radius: 50%;
}
.splatter-star {
width: 1.8em;
height: 1.8em;
background-image: url('data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" fill="%23006dd0" viewBox="0 0 24 24"%3E%3Cpath%20d%3D%22M12%2C17.27L18.18%2C21L16.54%2C13.97L22%2C9.24L14.81%2C8.62L12%2C2L9.19%2C8.62L2%2C9.24L7.45%2C13.97L5.82%2C21L12%2C17.27Z%22%3E%3C%2Fpath%3E%3C/svg%3E');
}
Javascript :
Vue.component('ti-button-splatter', {
props: ['text'],
data: function () {
return {
splatters: [] };
},
template: `
<button
class="btn-splatter"
v-on:click="makeSplatter(event)"
>
{{text}}
<div
v-for="splatter, i in splatters"
v-bind:class="splatter.type"
v-bind:style="splatter.style"
v-bind:ref="createRef(i)"
></div>
</button>
`,
methods: {
createRef: function (i) {
return 'splatter-' + i;
},
getSizeEm: function (s) {
if (s === 0) {
return 1 / 2 + 'em';
} else if (s === 1) {
return 1.5 / 2 + 'em';
} else if (s === 2) {
return 1.8 / 2 + 'em';
} else {
return 0;
}
},
createToXPos: function (tb, w, h, s) {
let positionStyle = { style: {} };
let randomPosition = Math.floor(Math.random() * w);
let fixedPosition = tb === 0 ? h : 0;
positionStyle.style.top = 'calc(' + fixedPosition + 'px - ' + s + ')';
positionStyle.style.left = 'calc(' + randomPosition + 'px - ' + s + ')';
return positionStyle;
},
createToYPos: function (lr, w, h, s) {
let positionStyle = { style: {} };
let randomPosition = Math.floor(Math.random() * h);
let fixedPosition = lr === 0 ? w : 0;
positionStyle.style.left = 'calc(' + fixedPosition + 'px - ' + s + ')';
positionStyle.style.top = 'calc(' + randomPosition + 'px - ' + s + ')';
return positionStyle;
},
createsplatter: function (el, count, types, w, h) {
for (let i = 0; i < count; i++) {if (window.CP.shouldStopExecution(0)) break;
let type = Math.floor(Math.random() * 3);
let xOrY = Math.round(Math.random());
let tblr = Math.round(Math.random());
let splt = null;
let sz = Math.random() + 0.5;
if (xOrY === 0) {
splt = this.createToXPos(tblr, w, h, this.getSizeEm(type));
} else {
splt = this.createToYPos(tblr, w, h, this.getSizeEm(type));
}
splt.type = types[type];
splt.scale = sz;
splt.style.display = 'none';
splt.style.transform = 'scale(' + sz + ')';
if (splt !== null) {
this.splatters.push(splt);
}
}window.CP.exitedLoop(0);
},
explodeSplatter: function () {
for (var i = 0; i < this.splatters.length; i++) {if (window.CP.shouldStopExecution(1)) break;
if (this.splatters[i].animationEnd === true) {
continue;
}
if (typeof this.splatters[i].moving === 'undefined') {
let el = this.$refs['splatter-' + i];
let an = Math.floor(Math.random() * 359) + 1;
this.splatters[i].style.display = 'block';
this.splatters[i].moving = true;
let psY = Math.sin(an) * 3 + 'em';
let psX = Math.cos(an) * 3 + 'em';
let scl = this.splatters[i].scale;
TweenLite.to(el, 0.8, {
transform:
'translate(' + psX + ', ' + psY + ') rotate(720deg) scale(0)' }).
eventCallback('onComplete', () => {
el.dataset.animationEnd = true;
});
}
}window.CP.exitedLoop(1);
},
makeSplatter: function (e) {
let el = e.target;
let count = Math.floor(Math.random() * 4) + 5;
let types = ['splatter-round', 'splatter-ring', 'splatter-star'];
let w = el.clientWidth;
let h = el.clientHeight;
this.createsplatter(el, count, types, w, h);
} },
watch: {
splatters: function (newData, oldData) {
setTimeout(() => {
this.explodeSplatter();
}, 1);
} } });
// -----
var app = new Vue({
el: '#app' });
- 이전글3D carousel 20.01.10
- 다음글Random Password Generator 20.01.10