如何在我的Component with Angular 4中实现更好的MouseEvent实现?

时间:2017-07-14 20:28:49

标签: css angular typescript

我有这个工作Plunker例如,你可以拖动鼠标并选择卡片。

  

我的问题是代码中有很多错误,我想这样做   与此Demo

类似的内容

这里有我要修复的内容(img1img2 - img#2中的卡片之前点击过),另一件事是如果你快速拖动鼠标,卡片将不会选择。

这是我的组件代码

export class App {

  private dragStart:number = 0;
  private dragOver:number = 0;
  public users:Array<{id?: number; name: string; admin: boolean;}> = [
        { name: 'Alexis Wursten', admin: false  },
        { name: 'Janco Boscan', admin: true  },
        { name: 'Noemi Iturralde', admin: false  },
    ];
  public added: string[] = [];
  x1 = 0; y1 = 0; x2 = 0; y2 = 0;

  @ViewChild('selector') selector: ElementRef;

  constructor(private renderer: Renderer2) {
  }

  isRectangeVisible = false;
  isMouseDown = false;

  @HostListener('mousedown', ['$event'])
  onMouseDown(ev) {
    this.dragStart = ev.clientY;
    this.isMouseDown = true;

  }

  @HostListener('document:mouseup', ['$event'])
  onMouseUp(ev) {
    this.dragStart = 0;
    this.dragOver = 0;
    this.renderer.setStyle(this.selector.nativeElement, 'display', 'none');
    this.isRectangeVisible = false;
    this.isMouseDown = false;
  }

  @HostListener('document:mousemove', ['$event'])
  onMouseMove(ev) {

    if(!this.isRectangeVisible && this.isMouseDown){
      this.renderer.setStyle(this.selector.nativeElement, 'display', 'block');
      this.x1 = ev.clientX;
      this.y1 = ev.clientY;
      this.isRectangeVisible = true;
    }

    this.x2 = ev.clientX;
    this.y2 = ev.clientY;
    this.reCalc();
  }

  reCalc() {
    const x3 = Math.min(this.x1, this.x2);
    const x4 = Math.max(this.x1, this.x2);
    const y3 = Math.min(this.y1, this.y2);
    const y4 = Math.max(this.y1, this.y2);
    this.renderer.setStyle(this.selector.nativeElement, 'left', x3 + 'px');
    this.renderer.setStyle(this.selector.nativeElement, 'top', y3 + 'px');
    this.renderer.setStyle(this.selector.nativeElement, 'width', x4 - x3 + 'px');
    this.renderer.setStyle(this.selector.nativeElement, 'height', y4 - y3 + 'px');
  }

  onSelecUser(item) {
        if(this.added.indexOf(item.name)===-1) { // or compare by id
            this.added = this.added.concat([item.name]);
        }
        else {
            this.added = this.added.filter((x) => item.name!==x); // or compare by id
        }

        item.selected = !item.selected ? true : false;
    }

    onMouseOver(ev, item) {
        if(ev.which!==1) {
            return false;
        }

        ev.preventDefault();

        if(ev.type==='mouseenter' && !item.selected) {
            this.dragOver = ev.clientY - this.dragStart > 0 ? 1:-1;
            this.onSelecUser(item);
            return false;
        }

        if(ev.type==='mouseleave') {
            if(this.dragOver===1 && ev.clientY < ev.target.offsetTop && item.selected) {
                console.log('desel...', item);
                this.onSelecUser(item);
                return false;
            }
            if(this.dragOver===-1 && ev.clientY > ev.target.offsetTop && item.selected) {
                console.log('desel...', item);
                this.onSelecUser(item);
                return false;
            }
        }
    }
}

感谢您阅读。

1 个答案:

答案 0 :(得分:2)

更新#1: https://plnkr.co/edit/d9aTb0E0OKFfTSIAM0MY?p=preview

添加了通过单击选择/取消选择用户的选项 为此,不需要重置代码。

  @HostListener('mousedown', ['$event'])
  onMouseDown(ev) {
    this.dragStart = ev.clientY;
    this.isMouseDown = true;
  }

只有div的点击处理程序已更改。

(click)="onSelecPersona(user, !user.selected)"

INITIAL ANSWER: 以下是修改后的代码:https://plnkr.co/edit/QryFWtLQwNuGkrtzDehm?p=preview

它解决了一些问题:

(1)HTML选择:“用户选择”CSS应位于“卡”上的“行”号上,因为选择从“行”边界开始

.row {
  user-select: none;
  -moz-user-select: none;
}
.card-content {
  padding: 0;
}

(2)处理选定的div:初始实现依赖于用户div上的鼠标事件。当“选择器”矩形永远不会越过“用户”div的边界(即绕过但仍然在选择边界内)时,这不处理这种情况。 我的实现计算“选择器”和“用户”div的重叠,以确定用户是否选择了。

     <div class="card"
            #ucard   
            [attr.id]="user.name"
            [class.selected]="user.selected" 
            *ngFor="let user of users" 
            (click)="onSelecPersona(user, !user.selected)"
        >

    import {Component, NgModule, HostListener, Renderer2, ElementRef, ViewChild, ViewChildren } from '@angular/core'
    ...
     @ViewChildren('ucard') components: QueryList<ElementRef>;
    ...
      // return true if two HTML elements overlap 
      overlap(e1:ElementRef, e2:ElementRef){
        var rect1 = e1.getBoundingClientRect();
        var rect2 = e2.getBoundingClientRect();

        return !(
          rect1.top > rect2.bottom ||
          rect1.right < rect2.left ||
          rect1.bottom < rect2.top ||
          rect1.left > rect2.right
        ); 
      }

      // updates user selection based on the current "selector" 
      markSelected(){
        this.components.forEach(it=> {
          var overlaps: boolean = this.overlap(this.selector.nativeElement, it.nativeElement);
          this.onSelecPersona(this.users.find(u=> u.name == it.nativeElement.id), overlaps);
        });
      }