首页 > 解决方案 > 如何在角材料表中获得选定区域?

问题描述

我想允许用户选择角表中的区域,如 Excel 表。如下图所示

在此处输入图像描述

我在点击时实现了多选行。

堆栈闪电战 | 多选行

我不确定如何进行。

我发现了一些类似的插件,但不知道如何在 Angular 中实现

  1. 带有 jQ​​uery 的 Excel 样式的表格单元格选择器插件 - TableCellsSelection
  2. 表选择 | CKEditor.com

任何帮助,建议表示赞赏

标签: angularangular-material

解决方案


但它并不是那么复杂,它是stackblitz吗

如果我们的 tds 像

<ng-container matColumnDef="position">
    <th mat-header-cell *matHeaderCellDef> No. </th>
    <td mat-cell #cell  *matCellDef="let element;let i=index" 
    (click)="select($event,cell)"
    <!--use isSelected(i,0) for the first column
            isSelected(i,1) for the second column
            ...
    -->
    [ngClass]="{'selected':isSelected(i,0)}"
    > {{element.position}} </td>
</ng-container>

我们使用 viewChildren 获取单元格,并使用选择声明一个数组

  selection: number[]=[];
  @ViewChildren("cell", { read: ElementRef }) cells: QueryList<ElementRef>;

在单元格中,我们有从上到下和从左到右的所有“td”顺序

如果您按下 shifh 键或 control 键,该功能选择会考虑在内

  select(event: MouseEvent, cell: any) {
    //search the cell "clicked"
    const cellClick = this.cells.find(x => x.nativeElement == event.target);

    //get the index of this cells
    let indexSelected = -1;
    this.cells.forEach((x, i) => {
      if (x == cellClick) indexSelected = i;
    });

   
    if (event.ctrlKey) { //if ctrl pressed

      if (this.selection.indexOf(indexSelected)>=0) //if its yet selected
        this.selection=this.selection.filter(x=>x!=indexSelected);
      else                                          //if it's not selected
        this.selection.push(indexSelected)
    } else {
      if (event.shiftKey) {    //if the key shift is pressed
        if (this.selection.length)      //if there any more selected
        {

          //calculate the row and col of fisrt element we selected
          let rowFrom=this.selection[0]%this.dataSource.data.length;
          let colFrom=Math.floor(this.selection[0]/this.dataSource.data.length)

          //idem from the index selected
          let rowTo=indexSelected%this.dataSource.data.length;
          let colTo=Math.floor(indexSelected/this.dataSource.data.length)

           //interchange if from is greater than to
          if (rowFrom>rowTo)
            [rowFrom, rowTo] = [rowTo, rowFrom]
          if (colFrom>colTo)
            [colFrom, colTo] = [colTo, colFrom]

          //clean the array
          this.selection=[]

          //we run througth all the td to check if we need push or not
          this.cells.forEach((x,index)=>{
            const row=index%this.dataSource.data.length;
            const col=Math.floor(index/this.dataSource.data.length)
            if (row>=rowFrom && row<=rowTo && col>=colFrom && col<=colTo)
              this.selection.push(index)
          })
        }
        else   //if there're anything selected and the shit is pressed
        this.selection = [indexSelected]
      } else {  //if no key shit nor key ctrl
        this.selection = [indexSelected]
      }
    }
  }

并且一个函数 isSelected 提供了改变类的可能性

  isSelected(row,column)
  {
    const index=column*this.dataSource.data.length+row
    return this.selection.indexOf(index)>=0
  }

带有 .css

table {
    -webkit-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}
td { 
  outline: none!important 
}
.selected
{
  border:1px solid red;
}

更新

在您需要的示例shift & ctrl中。但是我们可以有一个复选框或一个选择来“改变选择方式” - 使用 [(ngModel)] - 并替换条件 event.shiftKey 和 event.ctrlKey。

如果你总是选择一个范围,你可以使用两个变量“fromIndex”和“toIndex”,

fromIndex:number=-1
toIndex:number=-1

select(event: MouseEvent, cell: any){
   ....
  ..get the indexSelected ...
  if (this.fromIndex==-1){ //If nothing select
     this.fromIndex=indexSelected
     this.toIndex=-1
  }
  else{
     this.toIndex=indexSelected;
  }
  if (this.toIndex>=0 && this.fromIndex>=0)
  {
      ...the code to select range
  }
} 

 

推荐阅读