Я ищу работающую виртуальную таблицу прокрутки с фиксированными заголовками, поэтому я нашел Cdk, который великолепен, но документацию действительно сложно понять. На данный момент я пытаюсь совместить CdkTable с CdkVirtualScoll.
Все рабочие примеры, которые я мог найти, используют таблицу материалов, но я этого не делаю.
Итак, как я могу заставить CdkVirtualScoll приступить к работе? Вот что я сделал до сих пор (из примеров):
<cdk-virtual-scroll-viewport>
<cdk-table [dataSource] = "dataSource">
<ng-container cdkColumnDef = "username">
<cdk-header-cell *cdkHeaderCellDef> User name </cdk-header-cell>
<cdk-cell *cdkCellDef = "let row"> {{row.username}} </cdk-cell>
</ng-container>
<ng-container cdkColumnDef = "title">
<cdk-header-cell *cdkHeaderCellDef> Title </cdk-header-cell>
<cdk-cell *cdkCellDef = "let row"> {{row.title}} </cdk-cell>
</ng-container>
<!-- Header and Row Declarations -->
<cdk-header-row *cdkHeaderRowDef = "['username', 'age']"></cdk-header-row>
<cdk-row *cdkRowDef = "let row; columns: ['username', 'age']"></cdk-row>
</cdk-table>
</cdk-virtual-scroll-viewport>
Как в документации написано, таблица была завернута в прокручиваемый вьюпорт. Но как и где я могу установить *cdkVirtualForсейчас?
Спасибо за вашу помощь!
@AmirArbabian: я уже сделал и потратил час работы, чтобы заставить его работать, но это не так. Разве нет действительно повторного использования примера с простым кодом?
Попробуйте, например, Вот этот.
@AmirArbabian: извините, мой ответ был неправильным: я запустил код (как в примере), но проблема по-прежнему в том, что заголовок НЕ фиксирован, а перемещается.
Ларс Хаген. Привет. там, как я могу связаться с вами? Мне нужна помощь с cdk-virtual-scroll.
@mex Я создал чат чат.stackoverflow.com/rooms/215503/мекс
Спасибо, Ларс. Он работает идеально. Спасибо за уделенное время.
Привет. Ларс. Мне нужна помощь с ngx-virtual scroll. Как я могу добавить обычную горизонтальную полосу прокрутки для таблицы с ngx-virtual scroll, если происходит переполнение в направлении x?





Поскольку я не смог найти реально работающее решение, я написал свой собственный «быстрый и грязный» код для фиксированного заголовка. Тем не менее, я надеюсь найти гораздо лучший способ в будущем. Возможно, следующий выпуск Cdk предложит решение.
Что я сделал сейчас, так это написал (более или менее хакерскую) директиву, которая клонирует таблицу изнутри cdk-virtual-scroll-viewport и размещает клонированный узел раньше. На следующем шаге visibility элемента table thead устанавливается на collapse.
Использование:
<cdk-virtual-scroll-viewport [itemSize] = "30" cloneThead>
<table class = "table table-hover">
<thead>
...
</thead>
<tbody>
<tr *cdkVirtualFor = "let item of list">
<td>...</td>
...
</tr>
</tbody>
</table>
</cdk-virtual-scroll-viewport>
Директива cloneThead довольно проста:
import { Directive, AfterViewInit, ElementRef } from '@angular/core';
@Directive({
selector: '[cloneThead]'
})
export class CloneDirective implements AfterViewInit{
constructor(private el: ElementRef) {}
ngAfterViewInit(){
let cloned = this.el.nativeElement.cloneNode(true);
let table = cloned.querySelector("table");
table.style.position = 'sticky';
table.style.top = '0';
table.style.zIndex = '100';
this.el.nativeElement.appendChild(table);
}
}
Это работает очень хорошо, но все еще имеет одну большую проблему: клон создается после ngAfterViewInit, что приводит к тому, что строки таблицы cdkVirtualFor еще не созданы в DOM.
Это хорошо для самого клона, потому что он еще не содержит tr элементов tbody, НО вычисленные стили CSS для правильной ширины для th элементов также неизвестны.
Поэтому все элементы th должны иметь атрибут ширины CSS. В противном случае th ширина и td ширина могут отличаться - что выглядит некрасиво...
Может быть, у кого-то есть решение сделать «настоящий» клон после того, как cdk-virtual-scroll-viewport-таблица будет нарисована.
Вот обновленное решение
большая проблема предыдущего кода заключалась в том, что он не мог динамически вычислять ширину столбцов. Поэтому было необходимо указать with для каждого столбца.
Эта версия исправляет эту проблему.
@Directive({
selector: '[cdkFixedHeader]'
})
export class FixedHeaderDirective implements AfterViewInit{
constructor(private el: ElementRef, private renderer:Renderer2) {}
ngAfterViewInit(){
// get the viewport element
let cdkViewport = this.el.nativeElement.closest("cdk-virtual-scroll-viewport");
// check if table was already cloned
let clonedHeader = cdkViewport.querySelectorAll('.cloned-header');
// create a clone if not exists
if (clonedHeader.length == 0)
{
let table = this.el.nativeElement.closest('table');
let cloned = table.cloneNode(true);
cloned.style.position = 'sticky';
cloned.style.top = '0';
cloned.style.zIndex = '100';
// remove tbody with elements
let tbody = cloned.querySelector('tbody');
cloned.removeChild(tbody);
// add a "helper" class
this.renderer.addClass(cloned, "cloned-header");
// append cloned object to viewport
cdkViewport.appendChild(cloned);
}
//
// walk through all <tr> with their <td> and store the max value in an array
//
let width = [];
let td = this.el.nativeElement.querySelectorAll("td");
width = new Array(td.length).fill(0);
td.forEach((item,index) => {
const w = item.getBoundingClientRect().width;
width[index] = Math.max(w, width[index]);
})
//
// get <th> elements and apply the max-width values
//
let th = cdkViewport.querySelectorAll('.cloned-header th');
th.forEach((item,index) => {
this.renderer.setStyle(item, "min-width", width[index] + 'px')
})
}
}
Использование:
Использование было немного изменено, потому что это было необходимо для вызова директивы при обработке *cdkVirtualFor.
<tr *cdkVirtualFor = "let item of list" cdkFixedHeader>
...
</tr>
Вот и все! Не очень красиво, но работает...
Взгляните на это обсуждение, возможно, оно поможет ссылка на сайт