«Сохранить» эффект пульсации до наведения курсора мыши

#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>