WedX - журнал о программировании и компьютерных науках

Angular: я хочу переместить фокус div с другого на кнопки со стрелками.

Я работаю над проектом angular и пришел к ситуации, когда у меня есть серия div в строке, и когда пользователь нажимает на любой div, он должен иметь возможность переходить от одного div к другому с помощью клавиши со стрелкой.

Пожалуйста помоги.

Я пробовал использовать событие нажатия клавиши, но мне это не помогло. Пытался найти похожие вопросы о stackoverflow, но все ответы были в jquery, и мне это нужно в машинописном тексте.

moveCell(e){
  console.log(e);
}
.container{
width: 100%;
}

.cell{
width: 100px;
float:left;
}

.cell:hover,
.cell:focus{
background: red;
}
<div class="container">
<div class="cell" (keypress)="moveCell($event)">cell 1</div>
  <div class="cell" (keypress)="moveCell($event)">cell 2</div>
  <div class="cell" (keypress)="moveCell($event)">cell 3</div>
  <div class="cell" (keypress)="moveCell($event)">cell 4</div>
  <div class="cell" (keypress)="moveCell($event)">cell 5</div>
  <div class="cell" (keypress)="moveCell($event)">cell 6</div>
  <div class="cell" (keypress)="moveCell($event)">cell 7</div>
  <div class="cell" (keypress)="moveCell($event)">cell 8</div>
  <div class="cell" (keypress)="moveCell($event)">cell 9</div>
</div>

В моем коде. Если пользователь нажимает на ячейку 2, фокус должен автоматически переходить в ячейку 2. После этого, если пользователь использует клавиатуру и нажимает клавиши со стрелками, он должен переместить фокус на следующую / предыдущую ячейку.


Ответы:


1

keypress не обнаруживает arrow keys, вместо этого используйте keydown. Чтобы получить фокус и прослушать ключевые события, добавьте атрибут tabindex в блоки div.

Для клавиши со стрелкой вправо вам нужно проверить, не является ли текущий активный элемент последним элементом, и сменить фокус на следующий элемент.

Для клавиши со стрелкой влево проверьте, не является ли текущий активный элемент первым элементом, а затем измените фокус на предыдущий элемент.

--HTML--

<div class="container">
  <div tabindex="0" class="cell" (keydown)="moveCell($event)">cell 2</div>
  <div tabindex="1" class="cell" (keydown)="moveCell($event)">cell 3</div>
  <div tabindex="2" class="cell" (keydown)="moveCell($event)">cell 4</div>
  <div tabindex="3" class="cell" (keydown)="moveCell($event)">cell 5</div>
  <div tabindex="4" class="cell" (keydown)="moveCell($event)">cell 6</div>
  <div tabindex="5" class="cell" (keydown)="moveCell($event)">cell 7</div>
  <div tabindex="6" class="cell" (keydown)="moveCell($event)">cell 8</div>
</div>

--Код компонента--

  length: 0;
  domEles;
  moveCell(e){
    const activeEle = document.activeElement;
    const activeEleIndex = Array.prototype.indexOf.call(this.domEles, activeEle);
    if(e.key == "ArrowRight" && activeEleIndex < this.length - 1 ) {
        activeEle.nextElementSibling.focus();
    } 

    if(e.key == "ArrowLeft" && activeEleIndex > 0) {
       activeEle.previousElementSibling.focus();
    }
  }

  ngOnInit() {
    this.domEles = document.querySelectorAll('.container > *');
    this.length = this.domEles.length;
  }

Working Code - https://stackblitz.com/edit/angular-5qxicw.

15.06.2019

2

Есть еще один подход с использованием директивы. Идея состоит в том, что мы получаем весь div с нашей директивой в нашем app.component с помощью ViewChildren, затем наш div с директивой отправляет событие и вызывает функцию нашего app.component. Таким образом, app.component становится похожим на

<div arrow-div (event)="handler($event)>my div</div>
<div arrow-div (event)="handler($event)>my div</div>
...

Но мы можем использовать «сервис», чтобы сделать вещи более «прозрачными».

Представьте себе такую ​​услугу, как

@Injectable({
  providedIn: 'root',
})
export class KeyBoardService {
  keyBoard:Subject<any>=new Subject<any>();
  sendMessage(message:any)
  {
    this.keyBoard.next(message)
  }
}

Наша директива может вызывать службу sendMessage при нажатии стрелки на клавиатуре, и в нашем app.component подписаться на эту службу. а затем наш app.component похож на

<div arrow-div >my div</div>
<div arrow-div >my div</div>
<br/>
<div arrow-div >my div</div>
<div arrow-div >my div</div>

Мы избегаем этого "уродливого" (event) = "handler ($ event)" в наших div !!

Ну, директива проста, используя @Hostlistener для прослушивания ключа и renderer2 для добавления атрибута tabindex (чтобы сделать div фокусируемым, нам нужно добавить tabIndex). Так

@Directive({
  selector: '[arrow-div]',
})
export class ArrowDivDirective {
  constructor(private keyboardService: KeyBoardService, public element: ElementRef, private render: Renderer2) {
    this.render.setAttribute(this.element.nativeElement, "tabindex", "0")
  }


  @HostListener('keydown', ['$event']) onKeyUp(e) {

    switch (e.keyCode) {
      case 38:
        this.keyboardService.sendMessage({ element: this.element, action: 'UP' })
        break;
      case 37:
        this.keyboardService.sendMessage({ element: this.element, action: 'LEFT' })
        break;
      case 40:
        this.keyboardService.sendMessage({ element: this.element, action: 'DOWN' })
        break;
      case 39:
        this.keyboardService.sendMessage({ element: this.element, action: 'RIGTH' })
        break;
    }
  }
}

И наш app.component.ts

export class AppComponent implements OnInit {
  columns:number=2;
  @ViewChildren(ArrowDivDirective) inputs:QueryList<ArrowDivDirective>

  constructor(private keyboardService:KeyBoardService){}
  ngOnInit()
  {
    this.keyboardService.keyBoard.subscribe(res=>{
      this.move(res)
    })
  }
  move(object)
  {
    const inputToArray=this.inputs.toArray()
    let index=inputToArray.findIndex(x=>x.element==object.element);
    switch (object.action)
    {
      case "UP":
        index-=this.columns;
        break;
      case "DOWN":
        index+=this.columns;
        break;
      case "LEFT":
        index--;
        break;
      case "RIGTH":
        index++;
        break;
      case "RIGTH":
        index++;
        break;
    }

    if (index>=0 && index<this.inputs.length)
      inputToArray[index].element.nativeElement.focus();
  }
}

Обратите внимание, что я использовал переменную «столбец», если мы создаем «сетку» с столбцами и строками и используем клавиши вверх и вниз для перемещения между строками. Отправляя «элемент», избегайте того, чтобы мы сохранили «сфокусированный на div»

Вы можете увидеть пример в stackblitz.

16.06.2019
Новые материалы

Как создать диаграмму градиентной кисти с помощью D3.js
Резюме: Из этого туториала Вы узнаете, как добавить градиентную кисть к диаграмме с областями в D3.js. Мы добавим градиент к значениям SVG и применим градиент в качестве заливки к диаграмме с..

Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что это выглядит сложно…
Просто начните и учитесь самостоятельно Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что он кажется мне сложным, и я бросил его. Это в основном инструмент..

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

Объяснение документов 02: BERT
BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

Как проанализировать работу вашего классификатора?
Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

Работа с цепями Маркова, часть 4 (Машинное обучение)
Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..


Для любых предложений по сайту: [email protected]