材质角度滚动到垫层列表上的元素

时间:2019-01-22 14:54:32

标签: angular scroll angular-material material-design

我有一个包含多个元素的Angular Material列表,可以在其中选择一个元素。

当我加载该列表时,我想将列表向上滚动到所选元素,以使其更加可见。有什么选择吗?

我当时正在考虑类似ngOnInit来检查是否选中了该项目,但是我真的不知道如何将列表向上滚动到该项目。

注意:不是整个页面都应该滚动,只滚动列表中的元素。

component.html

<mat-nav-list>
    <mat-list-item *ngFor="let item of items" (click)="itemClick(item)"
        [ngClass]="item.selectedClass">
        {{item.someValue}}
    </mat-list-item>
</mat-nav-list>

component.ts

private itemClick(item: Item): Observable<any> {
    if (item) {
        this.something = item;
        this.items.forEach(item => {
            if (item && item.name === item.name) {
                item["selectedClass"] = "item-selected";
            } else {
                item["selectedClass"] = undefined;
            }
        });
    } else {
        this.something = null;
        this.items.forEach(item => {
                item["selectedClass"] = undefined;
        });
    }

    return of(null);
}

3 个答案:

答案 0 :(得分:1)

您可以在 scrollIntoView 中使用指令方法:

@Directive({
  selector: '[appScrollIntoView]'
})
export class ScrollIntoViewDirective implements OnChanges {
  @Input() appScrollIntoView: boolean | undefined;

  constructor(
    @Inject(PLATFORM_ID) private platformId: any,
    private elementRef: ElementRef
  ) {}

  ngOnChanges(simpleChange: SimpleChanges) {
    if (isPlatformBrowser(this.platformId)) {
      if (coerceBooleanProperty(this.appScrollIntoView)) {
        (this.elementRef.nativeElement as HTMLInputElement).scrollIntoView({
          behavior: 'smooth',
          block: 'center'
        });
      }
    }
  }
}

用法:

  <mat-list class="list" role="list">
    <mat-list-item
      class="list-item"
      [class.selected]="item === selectedItem"
      [appScrollIntoView]="item === selectedItem"
      *ngFor="let item of items"
      (click)="selectedItem = item"
      role="listitem"
      >{{ item.name }}</mat-list-item
    >
  </mat-list>

stackblitz

如果您使用材料选择列表,MatListOption 有一个 focus 方法,这是另一种选择。

@Directive({
  selector: 'mat-list-option[appScrollIntoView]'
})
export class ScrollIntoViewDirective implements OnChanges {
  @Input() appScrollIntoView: boolean | undefined;

  constructor(
    @Inject(PLATFORM_ID) private platformId: any,
    private elementRef: ElementRef,
    private matListOption: MatListOption
  ) {}

  ngOnChanges(simpleChange: SimpleChanges) {
    if (isPlatformBrowser(this.platformId)) {
      if (coerceBooleanProperty(this.appScrollIntoView)) {
        this.matListOption.focus();
      }
    }
  }
}

用法:

  <mat-selection-list
    (selectionChange)="selectedItem = $event.option.value"
    class="list"
    [multiple]="false"
    role="list"
    #itemList
  >
    <mat-list-option
      class="list-item"
      [appScrollIntoView]="option.selected"
      *ngFor="let item of items"
      role="listitem"
      [selected]="item === selectedItem"
      [value]="item"
      #option
      >{{ item.name }}</mat-list-option
    >
  </mat-selection-list>

stackblitz

答案 1 :(得分:0)

几乎没有代码,但是您可以给所有元素一个ID,也许像

然后使用ngOnInit检查您选择的元素,使用document.getElementById('listelement'+elementid)选择DOM元素并将其滚动到视图中。 经典的JS方法是element.scrollIntoView();

答案 2 :(得分:0)

查看此演示:https://stackblitz.com/edit/angular-yjbpoq?file=src%2Fapp%2Fhello.component.ts

要点是,您要将新指令附加到列表和每个列表项:

<mat-list appScrollable ...>
  <mat-list-item appOffsetTop ...>
  ...
  </mat-list-item>
</mat-list>

列表中的一个可以为列表设置scrollTop(或使用scrollTo或其他方式):

@Directive({selector: '[appScrollable]'})
export class ScrollableDirective {
  constructor(private _el: ElementRef) {}
  set scrollTop(value: number) { this._el.nativeElement.scrollTop = value; }
}

列表项中的一个可以报告其offsetTop

@Directive({ selector: '[appOffsetTop]'})
export class OffsetTopDirective {
  constructor(private _el: ElementRef) { }
  get offsetTop(): number { return this._el.nativeElement.offsetTop; }
}

通过@ViewChild@ViewChildren在组件中访问每种类型的指令:

  @ViewChildren(OffsetTopDirective) listItems: QueryList<OffsetTopDirective>;
  @ViewChild(ScrollableDirective) list: ScrollableDirective;

AfterViewInit生命周期挂钩中,将在项目列表中搜索与当前所选项目匹配的项目(此处出于说明目的在此处进行了随机设置)。然后将列表的scrollTop设置为该项目的offsetTop

  // Inside your component
  selectedItem = Math.floor(Math.random() * 500);
  items = new Array(500).fill(0).map((_, i) => `Item ${i}`);

  ngAfterViewInit() {
    this.list.scrollTop = this.listItems.find((_, i) => i === this.selectedItem).offsetTop;
  }