Угловое событие касания при наведении мыши при обработке множественного выбора
Я работаю с Angular 4, и у меня есть компонент, содержащий список <box>
компоненты. Мне нужно, чтобы пользователь мог выбрать несколько полей в родительском компоненте.
В первой версии я обрабатываю события мыши с помощью mousedown, mouseover and mouseup
, Для каждого события мыши a box component emits its id to the parent component
, Пользователь может выбрать несколько блоков, щелкнув блок и перетащив мышь на другие поля.
box.component.ts
import { Component, OnInit } from '@angular/core';
import { EventEmitter, Input, Output } from '@angular/core';
@Component({
selector: 'box',
styles: [`
`],
template: `
<div class="box-container"
(mousedown)="onMouseDown()"
(mouseover)="onMouseOver()"
(mouseup)="onMouseUp()">
{{ id }}
</div>
`
})
export class BoxComponent implements OnInit {
@Input() id: number;
@Output() mouseDown: EventEmitter<number>;
@Output() mouseOver: EventEmitter<number>;
@Output() mouseUp: EventEmitter<number>;
constructor() {
this.mouseDown = new EventEmitter<number>();
this.mouseOver = new EventEmitter<number>();
this.mouseUp = new EventEmitter<number>();
}
ngOnInit() {
}
onMouseDown(): void {
this.mouseDown.emit((this.id));
}
onMouseOver(): void {
this.mouseOver.emit((this.id));
}
onMouseUp(): void {
this.mouseUp.emit((this.id));
}
}
app.component.ts
@Component({
selector: 'my-app',
template: `
<div style="display: flex;">
<box *ngFor="let id of ids" [id]="id"
(mouseDown)="onMouseDown($event)"
(mouseOver)="onMouseOver($event)"
(mouseUp)="onMouseUp($event)">
</box>
</div>
<br>
<div style="display: flex;">
Selected Ids: <span *ngFor="let id of selectedIds" style="padding-left: 10px;">{{ id }}</span>
</div>
`,
})
export class App {
ids: [number];
enableTracking: boolean;
selectedIds: Set<number>;
constructor() {
this.enableTracking = false;
this.ids = [1, 2, 3, 4, 5];
this.selectedIds = new Set<number>();
}
onMouseDown(boxId: number): void {
this.enableTracking = true;
this.selectedIds.clear();
this.selectedIds.add(boxId);
}
onMouseOver(boxId: number): void {
if (this.enableTracking) {
this.selectedIds.add(boxId);
}
}
onMouseUp(boxId: number): void {
this.enableTracking = false;
console.log('Selected Ids: ' + JSON.stringify(this.selectedIds));
}
}
Во второй версии я пытаюсь добиться того же, используя сенсорные события: touchstart, touchmove and touchend
,
box.component.ts
import { Component, OnInit } from '@angular/core';
import { EventEmitter, Input, Output } from '@angular/core';
@Component({
selector: 'box',
styles: [`
`],
template: `
<div class="box-container"
(touchstart)="onTouchStart()"
(touchmove)="onTouchMove()"
(touchend)="onTouchEnd()">
{{ id }}
</div>
`
})
export class BoxComponent implements OnInit {
@Input() id: number;
@Output() touchStart: EventEmitter<number>;
@Output() touchMove: EventEmitter<number>;
@Output() touchEnd: EventEmitter<number>;
constructor() {
this.touchStart = new EventEmitter<number>();
this.touchMove = new EventEmitter<number>();
this.touchEnd = new EventEmitter<number>();
}
ngOnInit() {
}
onTouchStart(): void {
this.touchStart.emit((this.id));
}
onTouchMove(): void {
this.touchMove.emit((this.id));
}
onTouchEnd(): void {
this.touchEnd.emit((this.id));
}
}
app.component.ts
@Component({
selector: 'my-app',
template: `
<div style="display: flex;">
<box *ngFor="let id of ids" [id]="id"
(touchStart)="onTouchStart($event)"
(touchMove)="onTouchMove($event)"
(touchEnd)="onTouchEnd($event)">
</box>
</div>
<br>
<div style="display: flex;">
Selected Ids: <span *ngFor="let id of selectedIds" style="padding-left: 10px;">{{ id }}</span>
</div>
`,
})
export class App {
ids: [number];
enableTracking: boolean;
selectedIds: Set<number>;
constructor() {
this.enableTracking = false;
this.ids = [1, 2, 3, 4, 5];
this.selectedIds = new Set<number>();
}
onTouchStart(boxId: number): void {
this.enableTracking = true;
this.selectedIds.clear();
this.selectedIds.add(boxId);
}
onTouchMove(boxId: number): void {
if (this.enableTracking) {
this.selectedIds.add(boxId);
}
}
onTouchEnd(boxId: number): void {
this.enableTracking = false;
console.log('Selected Ids: ' + JSON.stringify(this.selectedIds));
}
}
Тем не менее, это не работает, как ожидалось, потому что touchmove
событие всегда испускают box-id associated to touchstart
событие. В первой версии каждый раз, когда я перехожу к другому компоненту коробки, mouseover
испускает идентификатор коробки current-active
коробочный компонент.
Как мне справиться с этим множественным выбором в сенсорных устройствах?
0 ответов
Немного поздно, но этот способ может быть полезен:
- Добавьте данные индекса в элемент DOM в качестве атрибута, который можно использовать для поиска элемента angular
- Используйте elementFromPoint, чтобы найти фактический элемент DOM, который вы ищете
- Анализируйте данные индекса из элемента и используйте их для выбора соответствующего углового элемента.
Я использую эту функцию, которая содержит некоторую фильтрацию:
public touchMoveHandler(event) {
// Allow dragging only if it was started on a specific sets of classes
if (!event.touches[0].target.classList.contains('free') || event.touches[0].target.classList.contains('inactive-for-user')) {
return;
}
// Prevent scroll by touch
event.preventDefault();
// Find the actual DOM element under the coordinates
const targetElement = (document.elementFromPoint(event.changedTouches[0].clientX, event.changedTouches[0].clientY));
// Only match elements that I want to listen
if (!targetElement.classList.contains('free')) {
return;
}
// Get element index attribute that points to my array
const id = targetElement['getAttribute']('data-block-index');
// Find it in my array
const currentBlock = this.blocks[id];
...
}
В HTML:
(touchmove)="touchMoveHandler($event)"
[attr.data-block-index]="i"
Не самый элегантный способ, лучше не нашел.