#javascript #vue.js #sass #material-design #vue-transitions
Вопрос:
Я пытаюсь воспроизвести эффект пульсации от Material Design, так как текущее приложение, над которым я работаю, собирается избавиться от Квазара; поэтому я создаю все элементы с нуля.
Я посмотрел несколько видеороликов, в которых это делается только в чистом CSS и JS, и я попытался преобразовать их в свой проект, но где-то застрял. У меня есть эффект наведения и правильная регистрация местоположения мыши, но эффект пульсации просто не срабатывает, и я не знаю, почему.
Любая помощь будет очень признательна! Ваше здоровье!
CButton.vue
<template>
<button
@click="onClick"
:class="[
'c-btn',
`c-btn--${kind}`,
disabled ? `_disabled` : '',
kind === 'icon-round' ? 'shadow-5' : '',
]"
>
<transition
name="ripple"
@enter="rippleEnter"
@after-enter="afterRippleEnter"
>
<span v-if="ripple" ref="ripple" class="ripple" />
</transition>
<div class="_inner">
<div class="_text">
<slot>{{ btnText }}</slot>
</div>
</div>
</button>
</template>
<script>
export default {
name: "CcBtn",
components: {},
props: {
btnText: { type: String },
kind: { type: String, default: "main" },
isBusy: { type: Boolean, default: false },
/**
* HTML5 attribute
* @category state
*/
disabled: { type: Boolean, default: false },
color: { type: String, default: "" },
},
data() {
return {
ripple: false,
x: 0,
y: 0,
};
},
methods: {
onClick(e) {
this.x = e.layerX;
this.y = e.layerY;
this.ripple = !this.ripple;
console.log(`x`, this.x);
console.log(`y`, this.y);
console.log(`ripple`, this.ripple);
},
rippleEnter() {
this.$refs.ripple.style.top = `${this.y}px`;
this.$refs.ripple.style.left = `${this.x}px`;
},
afterRippleEnter() {
this.ripple = false;
},
},
};
</script>
<style lang="sass" scoped>
.c-btn
color: white
padding: 10px 16px
border-radius: 4px
line-height: 1em
min-height: 2em
font-weight: bold
font-size: 16px
color: White
cursor: pointer
border: 1px solid transparent
transition: background-color 0.5s
._inner
display: flex
align-items: center
justify-content: center
amp;--main
background: #9759ff
min-width: 228px
border-radius: 100px
amp;:hover
background-color: lighten(#9759ff, 10%)
amp;--sub
background: #f3eefe
min-width: 228px
border-radius: 100px
color: black
amp;:hover
background-color: darken(#f3eefe, 5%)
.ripple
display: block
width: 20px
height: 20px
border-radius: 10px
position: absolute
top: 0
left: 0
pointer-events: none
background-color: rgba(lighten(#9759ff, 20%), 0.8)
opacity: 0
transform: translate(-50%, -50%) scale(10)
transition: opacity 0.4s ease-in-out, transform 0.4s ease-in-out
amp;-enter
opacity: 1
transform: translate(-50%, -50%) scale(0)
</style>
Приложение.vue
<template>
<CButton :btnText="'Button'" kind="main" />
<br />
<br />
<br />
<CButton :btnText="'Button'" kind="sub" />
</template>
<script>
import CButton from "./components/CButton.vue";
export default {
name: "App",
components: {
CButton,
},
};
</script>
Ответ №1:
Вот рабочий код для кнопки, которая оказывает волновой эффект при нажатии. Использование CSS и JS:
function createRipple(event) {
const button = event.currentTarget;
const circle = document.createElement("span");
const diameter = Math.max(button.clientWidth, button.clientHeight);
const radius = diameter / 2;
circle.style.width = circle.style.height = `${diameter}px`;
circle.style.left = `${event.clientX - button.offsetLeft - radius}px`;
circle.style.top = `${event.clientY - button.offsetTop - radius}px`;
circle.classList.add("ripple");
const ripple = button.getElementsByClassName("ripple")[0];
if (ripple) {
ripple.remove();
}
button.appendChild(circle);
}
const buttons = document.getElementsByTagName("button");
for (const button of buttons) {
button.addEventListener("click", createRipple);
}
body {
height: 100vh;
margin: 0;
display: grid;
place-items: center;
}
@import url('https://fonts.googleapis.com/css2?family=Robotoamp;display=swap');
button {
position: relative;
overflow: hidden;
transition: background 400ms;
color: #fff;
background-color: #ff0000;
padding: 1rem 2rem;
font-family: 'Roboto', sans-serif;
font-size: 1.5rem;
outline: 0;
border: 0;
border-radius: 0.25rem;
box-shadow: 0 0 0.5rem rgba(0, 0, 0, 0.3); /* black with 30% opacity */
cursor: pointer;
}
span.ripple {
position: absolute;
border-radius: 50%;
transform: scale(0);
animation: ripple 600ms linear;
background-color: rgba(255, 255, 255, 0.7);
}
@keyframes ripple {
to {
transform: scale(4);
opacity: 0;
}
}
<button>Click For Effect</button>
Комментарии:
1. Спасибо за код и комментарий! Тем не менее, я видел много таких, сделанных в codesandbox или где-то еще, и пытаюсь преобразовать их в Vue. Не знаю, где я сейчас ошибаюсь. Может быть, это потому, что я не использую ключевые кадры? В любом случае, я более внимательно посмотрю на ваш комментарий и посмотрю, не смогу ли я это понять