Обработка нажатия кнопки на клавиатуре

94
30 марта 2021, 13:50

При нажатии на кнопку стрелка (на клавиатуре) (keycode 37) нужно показать иконку на на 300мс, замет скрыть её. И так на каждое нажатие кнопки. Я создаю переменную с типом false при нажатии кнопки, делаю её true тем самым отображая иконку, при нажатии запускается запуская таймер на 300мс по истечению которого другая функция возвращает false, тем самым пряча иконку. Проблема заключается в том, что при частом многократном нажатии в какой-то момент иконка перестает появляться.

Может есть идеии как можно усовершенствовать этот подход или поменять на что-нибудь более толковое.

P.S. В css есть класс info_icons для иконки. Когда иконка появляется для неё срабатывает анимация, то есть из прозрачной она становится не прозрачной и затем опять прозрачной. Проще говоря она плавно появляется и исчезает.

P.P.S

Так же для других кнопок есть actions. Суть такая же. Я добавил один вариант, если получится придумать альтернативу или починить нижеизложенный код, то я смогу провернуть это дело с остальными кнопками :)

html

<v-icon v-if="replay_5" class="info_icons" size="50">
      replay_5
</v-icon> //Material ui icon

Vue

data() {
  return {
    replay_5: false,
  }
}
methods: {
  show_replay_5() {
    this.replay_5 = false;
  },
  onKeydown({
    keyCode
  }) {
    switch (keyCode) {
      case 37:
        this.replay_5 = true;
        /*some code*/
        setTimeout(this.show_replay_5, 300);
        break;
    }
  }
}

css

 .info_icons {
        animation-name: fadeInOpacity;
        animation-iteration-count: 1;
        animation-timing-function: ease-in;
        animation-duration: 0.3s;
        background-color: rgba(255, 255, 255, 0.3);
        border-radius: 100%;
        transform: scale(1.2);
        opacity: 0;
    }
    @keyframes fadeInOpacity {
        0% {
            opacity: 0;
        }
        50% {
            opacity: 1;
        }
        100% {
            opacity: 0;
        }
    }

Спасибо за внимание!

Answer 1

При использовании setTimeout и setInterval лучше создавать ссылки на них и при необходимости удалять, тогда не будет "зацикливаний".

Оптимальным было бы воспользоваться стандартными средствами анимации Vue: используя хук, например, enter, менять значение, отвечающее за показ элемента на противоположное и тем самым скрывать его. Демо:

// Создаем экземпляр приложения. 
new Vue({ 
  // Корневой элемент, определяется по css селектору. 
  el: '#app', 
  data: { 
    // Модель отображения кнопок-стрелок. 
    arrows: { 
      top: false, 
      bottom: false, 
      left: false, 
      right: false, 
    }, 
    // Чтобы не перебирать "свитчами" и "кейсами". 
    keyMap: { 
      37: 'left', 
      38: 'top', 
      39: 'right', 
      40: 'bottom', 
    } 
  }, 
  methods: { 
    onKeydown({ 
      keyCode 
    }) { 
      if (keyCode in this.keyMap) { 
        this.arrows[this.keyMap[keyCode]] = true; 
      } 
    }, 
 
    /** 
     * Появление. 
     */ 
    beforeEnter(el) { 
      // console.log('beforeEnter'); 
    }, 
    enter(el, done) { 
      // console.log('enter'); 
 
      // Перебираем свойства объекта, 
      // устанавливаем для всех полей значение `false`. 
      for (let arrow in this.arrows) { 
        if ('object' === typeof this.arrows && this.arrows.hasOwnProperty(arrow)) { 
          this.arrows[arrow] = false; 
        } 
      } 
      // Коллбэк done не обязательно использовать, если 
      // анимация или переход также определены в CSS. 
      // done(); 
    } 
  } 
});
/** 
 * Стили для анимации. 
 */ 
 
.fade-enter-active, 
.fade-leave-active { 
  animation: fade-in .6s; 
} 
 
@keyframes fade-in { 
  0% { 
    opacity: 0; 
  } 
  50% { 
    opacity: 1; 
  } 
  100% { 
    opacity: 0; 
  } 
} 
 
 
/* Или такой вариант 
.fade-enter-active, .fade-leave-active { transition: opacity .6s;} 
.fade-enter, .fade-leave-to { opacity: 0; } 
 */ 
 
 
/** 
 * Дальше стили для демки. 
 */ 
 
*, 
 ::after, 
 ::before { 
  box-sizing: border-box; 
  text-align: center; 
} 
 
.wrapper { 
  width: 188px; 
  border: 1px dashed #08c; 
  margin: 0 auto; 
  display: grid; 
  grid-template-areas: 'top top' 'left right' 'bottom bottom'; 
} 
 
.wrapper:focus { 
  border: 1px solid #08c; 
  outline: none; 
} 
 
.icon { 
  line-height: 60px; 
  min-height: 60px; 
  color: #fff; 
} 
 
.icon-top { 
  grid-area: top; 
} 
 
.color-top { 
  background: #fbc531; 
} 
 
.icon-left { 
  grid-area: left; 
} 
 
.color-left { 
  background: #c23616; 
} 
 
.icon-right { 
  grid-area: right; 
} 
 
.color-right { 
  background: #487eb0; 
} 
 
.icon-bottom { 
  grid-area: bottom; 
} 
 
.color-bottom { 
  background: #5fba7d; 
}
<div id="app"> 
  <h3>Щелкните на блок для захвата ввода с клавиатуры</h3> 
  <h4>Используйте стрелки клавиатуры, чтобы отобразить элементы</h4> 
 
  <div class="wrapper" @keydown="onKeydown" tabindex="-1"> 
    <div class="icon icon-top"> 
      <transition name="fade" @enter="enter"> 
        <div v-if="arrows.top" class="color-top">Север</div> 
      </transition> 
    </div> 
 
    <div class="icon icon-left"> 
      <transition name="fade" @enter="enter"> 
        <div v-if="arrows.left" class="color-left">Запад</div> 
      </transition> 
    </div> 
 
    <div class="icon icon-right"> 
      <transition name="fade" @enter="enter"> 
        <div v-if="arrows.right" class="color-right">Восток</div> 
      </transition> 
    </div> 
 
    <div class="icon icon-bottom"> 
      <transition name="fade" @enter="enter"> 
        <div v-if="arrows.bottom" class="color-bottom">Юг</div> 
      </transition> 
    </div> 
  </div> 
</div> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

В данном примере использованы повторяющиеся конструкции в HTML разметке, чтобы сохранить каркас для блоков, размещенных по сторонам света, т.е. это не шаблон, которому вы должны строго следовать.

READ ALSO
Разное выполнение функции через button и input

Разное выполнение функции через button и input

Подскажите что не так, при инициализации функции на input все работает, а вот через button нет, функция выполняется и сразу же "все пропадает"

113
Переполнение стека из-за статического конструктора

Переполнение стека из-за статического конструктора

У меня есть Timer, который по определенным причинам я проинициализировал в статическом конструктореПосле того как я добавил этот статический...

128
Xpath. Как добавить песню в vk.com?

Xpath. Как добавить песню в vk.com?

Пытаюсь c помощью XPath добавить песню в мои аудиозаписиПроблема в том, что кнопка добавления трека появляется только при наведении мышкой...

102
Выделение текста в TextBlock

Выделение текста в TextBlock

У меня есть кастомный TextBlock, который определяет ссылки в тексте и делает их кликабельнымиВозникла необходимость добавить возможность выделения...

124