DevGang
Авторизоваться

Освоение изменяемых по размеру столбцов в таблицах Angular

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

Введение

Добавление изменяемых по размеру столбцов в таблицу Angular Material подразумевает создание пользовательской директивы, которая прослушивает события мыши, позволяя пользователям щелкать и перетаскивать столбец, чтобы регулировать его ширину. Это дает пользователям гибкость, особенно при работе с большими наборами данных, улучшая пользовательский опыт.

В этом уроке мы:

  • Создадим пользовательскую директиву изменения размера столбца.
  • Обработаем события мыши для изменения размера столбцов.
  • Применим стили для удобства пользователя.
  • Прикрепим директиву к таблице материалов Angular.

Давайте углубимся в это.

Шаг 1: Настройка углового стола материалов

Во-первых, убедитесь, что в вашем проекте Angular установлен Angular Material. Если нет, выполните следующую команду, чтобы добавить Angular Material в ваш проект:

ng add @angular/material

После установки Angular Material вы можете создать простую таблицу, используя следующий код.

HTML для таблицы:

<div class="resizable-table">
  <table mat-table [dataSource]="dataSource">
    <ng-container *ngFor="let column of displayedColumns" [matColumnDef]="column">
      <th mat-header-cell *matHeaderCellDef appColumnResize>{{ column }}</th>
      <td mat-cell *matCellDef="let element">{{ element[column] }}</td>
    </ng-container>
    <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
    <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
  </table>
</div>

Здесь мы используем mat-table Angular Material для отображения простой таблицы. Директива appColumnResize применяется к th элементам (header), чтобы сделать столбцы изменяемыми по размеру.

Данные для таблицы:

import { Component, ViewEncapsulation } from '@angular/core';

export interface PeriodicElement {
  name: string;
  position: number;
  weight: number;
  symbol: string;
}

const ELEMENT_DATA: PeriodicElement[] = [
  { position: 1, name: 'Hydrogen', weight: 1.0079, symbol: 'H' },
  { position: 2, name: 'Helium', weight: 4.0026, symbol: 'He' },
  // ... add more data
];

@Component({
  selector: 'table-basic-example',
  styleUrls: ['table-basic-example.scss'],
  templateUrl: 'table-basic-example.html',
  encapsulation: ViewEncapsulation.None,
})
export class TableBasicExample {
  displayedColumns: string[] = ['position', 'name', 'weight', 'symbol'];
  dataSource = ELEMENT_DATA;
}

Компонент включает в себя данные по периодическим элементам, которые мы отобразим в таблице.

Шаг 2: Создание директивы изменения размера столбца

Далее мы реализуем пользовательскую директиву Angular, которая включает функцию изменения размера столбцов таблицы.

Реализация директивы:

import {
  Directive,
  ElementRef,
  Renderer2,
  NgZone,
  Input,
  OnInit,
  OnDestroy,
} from '@angular/core';
import { fromEvent, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

@Directive({
  selector: '[appColumnResize]',
})
export class ColumnResizeDirective implements OnInit, OnDestroy {
  @Input() resizableTable: HTMLElement | null = null;

  private startX!: number;
  private startWidth!: number;
  private isResizing = false;
  private column: HTMLElement;
  private resizer!: HTMLElement;
  private destroy$ = new Subject<void>();

  constructor(
    private el: ElementRef,
    private renderer: Renderer2,
    private zone: NgZone
  ) {
    this.column = this.el.nativeElement;
  }

  ngOnInit() {
    this.createResizer();
    this.initializeResizeListener();
  }

  private createResizer() {
    this.resizer = this.renderer.createElement('div');
    this.renderer.addClass(this.resizer, 'column-resizer');
    this.renderer.setStyle(this.resizer, 'position', 'absolute');
    this.renderer.setStyle(this.resizer, 'right', '0');
    this.renderer.setStyle(this.resizer, 'top', '0');
    this.renderer.setStyle(this.resizer, 'width', '5px');
    this.renderer.setStyle(this.resizer, 'cursor', 'col-resize');
    this.renderer.appendChild(this.column, this.resizer);
  }

  private initializeResizeListener() {
    this.zone.runOutsideAngular(() => {
      fromEvent(this.resizer, 'mousedown')
        .pipe(takeUntil(this.destroy$))
        .subscribe((event: MouseEvent) => this.onMouseDown(event));

      fromEvent(document, 'mousemove')
        .pipe(takeUntil(this.destroy$))
        .subscribe((event: MouseEvent) => this.onMouseMove(event));

      fromEvent(document, 'mouseup')
        .pipe(takeUntil(this.destroy$))
        .subscribe(() => this.onMouseUp());
    });
  }

  private onMouseDown(event: MouseEvent) {
    event.preventDefault();
    this.isResizing = true;
    this.startX = event.pageX;
    this.startWidth = this.column.offsetWidth;
  }

  private onMouseMove(event: MouseEvent) {
    if (!this.isResizing) return;
    const width = this.startWidth + (event.pageX - this.startX);
    this.renderer.setStyle(this.column, 'width', `${width}px`);
  }

  private onMouseUp() {
    if (!this.isResizing) return;
    this.isResizing = false;
  }

  ngOnDestroy() {
    this.destroy$.next();
    this.destroy$.complete();
  }
}

Объяснение:

  • createResizer(): Добавляет элемент изменения размера (div) к заголовку столбца.
  • onMouseDown(): Срабатывает, когда пользователь нажимает кнопку изменения размера, записывая начальное положение.
  • onMouseMove(): Обновляет ширину столбца по мере того, как пользователь перетаскивает регулятор размера.
  • onMouseUp(): Завершает изменение размера, когда пользователь отпускает кнопку мыши.

Шаг 3: Стилизация Resizer

Нам нужно стилизовать ресайзер, чтобы пользователи знали, что его можно перетаскивать. Добавьте следующий CSS в ваши стили:

.resizable-table {
  th {
    position: relative;

    .column-resizer {
      position: absolute;
      top: 0;
      right: 0;
      bottom: 0;
      width: 10px;
      cursor: col-resize;
      z-index: 1;

      &:hover {
        border-right: 2px solid red;
      }
    }

    &.resizing {
      user-select: none;
    }
  }

  &.resizing {
    cursor: col-resize;
    user-select: none;
  }
}

Этот CSS-код правильно позиционирует изменение размера, добавляет эффект наведения и изменяет курсор, чтобы указать на возможность изменения размера.

Шаг 4: Тестирование таблицы

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

Часто задаваемые вопросы?

В: Что произойдет, если таблица с изменяемым размером слишком широкая?

О: Таблица переполнится и подстроится под ширину контейнера. Убедитесь, что вы добавили правильное поведение прокрутки или корректировки контейнера для обработки больших таблиц.

В: Можно ли сделать определенные столбцы неизменяемыми по размеру?

О: Да, вы можете условно применить директивуappColumnResize только к определенным столбцам, используя встроенные структурные директивы Angular, такие как *ngIf.

В: Является ли этот подход производительным для больших таблиц?

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

Заключение

Следуя этому руководству, вы теперь имеете полностью функциональную функцию изменяемого размера столбцов для ваших таблиц Angular Material. Эта настройка повышает гибкость и удобство использования ваших таблиц, обеспечивая лучший пользовательский опыт. Счастливого кодирования!

#JavaScript #Angular #TypeScript
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу