#javascript
#javascript
Вопрос:
Я пытаюсь воссоздать эффект пульсации в material design. Вот мой код до сих пор:
$("html").on("mousedown", ".ripple-light", function(evt) {
var btnlight = $(evt.currentTarget);
var xx = evt.pageX - btnlight.offset().left;
var yy = evt.pageY - btnlight.offset().top;
var duration1 = 2000;
var animationFrame1, animationStart1;
var animationStep1 = function(timestamp1) {
if (!animationStart1) {
animationStart1 = timestamp1;
}
var frame1 = timestamp1 - animationStart1;
if (frame1 < duration1) {
var easing1 = (frame1/duration1) * (10 - (frame1/duration1));
var circle1 = "circle at " xx "px " yy "px";
var color1 = "rgba(255, 255, 255, .5)";
var stop1 = 99 * easing1 "%";
btnlight.css({
"background-image": "radial-gradient(" circle1 ", " color1 " " stop1 ", transparent " stop1 ")"
});
animationFrame1 = window.requestAnimationFrame(animationStep1);
} else {
$(btnlight).css({
"background-image": "none"
});
window.cancelAnimationFrame(animationFrame1);
}
};
animationFrame = window.requestAnimationFrame(animationStep1);
});
.btn {
padding: 10px 20px;
background: #2BBBAD;
color: white;
border: 0;
font-size: 15px;
box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12);
cursor: pointer;
border-radius: 4px;
outline: 0;
text-transform: uppercase;
user-select: none;
transition: all .2s;
}
.btn:hover,.btn:focus {
box-shadow: 0 2px 4px -1px rgba(0, 0, 0, 0.2), 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12);
}
.btn:active {
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2), 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12);
}
<script src="https://code.jquery.com/jquery-3.5.1.js" integrity="sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc=" crossorigin="anonymous"></script>
<button class="btn ripple-light">Hello, World! </button>
Итак, если вы заметили выше, пульсация работает, но после того, как вы отпустите мышь, она все еще там. Я хочу, чтобы этот эффект пульсации исчез после наведения курсора мыши.
Пока мышь нажата, я хочу, чтобы пульсация все еще отображалась. Эффект пульсации должен начинаться при наведении курсора мыши, удержании, а затем удаляться после наведения курсора мыши
Комментарии:
1. Как должна выглядеть кнопка при удалении анимации? Например. чтобы просто заставить ее исчезнуть в одном кадре, вы могли бы использовать
$("html").on("mouseup", ".ripple-light", evt => btnlight.css({ backgroundImage: 'none' }))
2. Хорошо, позвольте мне задать вам более подробный вопрос: 1 — Пользователь нажимает мышь вниз (это создает рябь) 2 — Пользователь все еще удерживает мышь нажатой (рябь все еще есть) 3 — Пользователь нажимает мышь вверх (рябь исчезает)
3. Вы заметили мой пример кода, где он создает пульсацию при наведении курсора мыши. Предполагается, что он «поддерживает» пульсацию при наведении курсора мыши и «удаляет» ее пульсацию при наведении курсора мыши
4. Чтобы заметить это, вам, вероятно, потребуется удерживать кнопку в течение 3 секунд
5. Я понимаю, что пульсация должна сохраняться до тех пор, пока кнопка есть
:active
, но какую анимацию вы хотите удалить, чтобы удалить пульсацию, когда кнопки больше:active
нет? Должен ли он исчезнуть в одном кадре?
Ответ №1:
Это может быть реализовано с использованием минимального количества javascript! Я надеюсь, что вы можете принять решение, основанное на 99% css, поскольку css дает большую гибкость для настройки вашей анимации по вкусу — во-первых, это позволяет нам использовать transition
свойство, которое автоматически обрабатывает отмену анимации, что является вашим основным запросом здесь.
Вот пример чистого css, где пульсация всегда возникает в верхнем левом углу кнопки; пульсация ::after
— это псевдоэлемент с transition
набором для его width
height
свойств и .
.button {
display: inline-block;
position: relative;
background-color: rgba(0, 150, 0, 1);
padding: 15px;
border-radius: 5px;
color: rgba(255, 255, 255, 1);
font-size: 200%;
font-family: monospace;
cursor: pointer;
overflow: hidden;
user-select: none;
}
.button::after {
content: ''; display: block; position: absolute;
left: 0; top: 0;
pointer-events: none;
background-color: rgba(255, 255, 255, 0.3);
width: 0; height: 0; margin-left: 0; margin-top: 0;
border-radius: 100%;
transition:
width 500ms ease-in-out,
height 500ms ease-in-out,
margin-left 500ms ease-in-out,
margin-top 500ms ease-in-out;
}
.button:active::after {
width: 500px; height: 500px;
margin-left: -250px; margin-top: -250px;
}
<div class="button">Click me :D</div>
Пульсация всегда возникает в верхнем левом углу, поскольку для его left
top
свойств и всегда установлено значение 0
.
Теперь мы можем параметризовать значения left
и top
, используя минимальное количество javascript, чтобы вызвать пульсацию в местоположении курсора:
let button = document.querySelector('.button');
button.addEventListener('mousemove', evt => {
let { left, top } = button.getBoundingClientRect();
let clickX = evt.pageX - left;
let clickY = evt.pageY - top;
button.style = `--rippleLeft: ${clickX}px; --rippleTop: ${clickY}px;`;
});
.button {
display: inline-block;
position: relative;
background-color: rgba(0, 150, 0, 1);
padding: 15px;
border-radius: 5px;
color: rgba(255, 255, 255, 1);
font-size: 200%;
font-family: monospace;
cursor: pointer;
overflow: hidden;
user-select: none;
}
.button::after {
content: ''; display: block; position: absolute;
left: var(--rippleLeft); top: var(--rippleTop);
pointer-events: none;
background-color: rgba(255, 255, 255, 0.3);
width: 0; height: 0; margin-left: 0; margin-top: 0;
border-radius: 100%;
transition:
width 500ms ease-in-out,
height 500ms ease-in-out,
margin-left 500ms ease-in-out,
margin-top 500ms ease-in-out;
}
.button:active::after {
width: 500px; height: 500px;
margin-left: -250px; margin-top: -250px;
}
<div class="button">Click me :D</div>
Мы можем использовать javascript, чтобы получить более точный контроль над тем, когда применяется переход — вместо использования :active
псевдокласса мы можем использовать события mouseup и mousedown для инициирования изменений css. Это позволяет нам предотвратить слишком раннее уменьшение пульсации:
let button = document.querySelector('.button');
// Ensure ripple originates at cursor
button.addEventListener('mousemove', evt => {
let { left, top } = button.getBoundingClientRect();
let clickX = evt.pageX - left;
let clickY = evt.pageY - top;
button.style = `--rippleLeft: ${clickX}px; --rippleTop: ${clickY}px;`;
});
// Control when ripple begins and ends
button.addEventListener('mousedown', evt => {
// Immediately begin growing ripple on mousedown
button.classList.add('active');
// Only remove "active" class when mouseup occurs, AND enough time has elapsed to
// allow the ripple to grow to its full size:
Promise.all([
new Promise(rsv => button.addEventListener('mouseup', rsv, { once: true })),
new Promise(rsv => setTimeout(rsv, 300))
])
.then(() => button.classList.remove('active'));
});
.button {
display: inline-block;
position: relative;
background-color: rgba(0, 150, 0, 1);
padding: 15px;
border-radius: 5px;
color: rgba(255, 255, 255, 1);
font-size: 200%;
font-family: monospace;
cursor: pointer;
overflow: hidden;
user-select: none;
}
.button::after {
content: ''; display: block; position: absolute;
left: var(--rippleLeft); top: var(--rippleTop);
pointer-events: none;
background-color: rgba(255, 255, 255, 0.3);
width: 0; height: 0; margin-left: 0; margin-top: 0;
border-radius: 100%;
transition:
width 300ms ease-in-out,
height 300ms ease-in-out,
margin-left 300ms ease-in-out,
margin-top 300ms ease-in-out;
}
.button.active::after {
width: 500px; height: 500px;
margin-left: -250px; margin-top: -250px;
}
<div class="button">Click me :D</div>