首页 > 解决方案 > 如何强制 Mat Tab 主体为非活动选项卡呈现/绑定 html 元素

问题描述

我正在使用 angular mat-tab-group 我如何强制 angular 绑定非活动选项卡的 html 元素,下面是 html 实现

<mat-tab label="Test">
    <app-test></app-test>
</mat-tab>

test.component.ts 文件确实初始化并运行,但 html 元素未绑定,请查看下面的附图。有没有办法强制角度绑定它?我正在集成一些需要在 component.ts 文件开始执行时绑定 html 元素的第 3 方库,否则它将中断。

在此处输入图像描述

标签: angularangular-material

解决方案


恐怕你不能,你可以使用事件(selectedTabChange)或(selectedIndexChange)。注意:如果你在@Output 中看到关于TabMatGroup的 API ,你有所有你可以“到达”的“事件”,你总是使用,例如(selectedTabChange)="yourFunction($event)",函数的参数是 API 中“EmitterEvent”下的指示 - 在这种情况下是类型MatTabChangeEvent-

存在另一个选项,即创建一个没有内容的选项卡组,并使用变量索引

//in your .ts
index=0

然后你创建一个 .html 像

    <!-- see that you use margin-bottom and animationDuration -->
    <mat-tab-group style="margin-bottom:5px;" animationDuration="0" 
               mat-align-tabs="start" (selectedIndexChange)="index=$event">
    <!-- you makes the mat-tabs "empty" -->
      <mat-tab label="First"></mat-tab>
      <mat-tab label="Second"></mat-tab>
      <mat-tab label="Third"></mat-tab>
    </mat-tab-group>
    <!--here you put your content using [style.display]="none" when 
        the index is not equal to hte value (remember index begings by 0-->
    <div [style.display]="index!=0?'none':null">
      Content 1
    </div>
    <div [style.display]="index!=1?'none':null">
    Content 2
    </div>
    <div [style.display]="index!=2?'none':null">
    Content 3
    </div>

但是您需要手动创建“动画”。为此,您可以将动画添加到组件中

  animations: [
    trigger('flyInOut', [
      transition(':decrement', [
        style({ transform: 'translateX(100%)' }),
        animate(200)
      ]),
      transition(':increment', [
        style({ transform: 'translateX(100%)' }),
        animate(200)
      ])
    ])
  ]

并使用辅助变量“indexOld”。然后在html中使用动画

<mat-tab-group style="margin-bottom:5px;" animationDuration="0" 
     mat-align-tabs="start" (selectedIndexChange)="index=$event">
  <mat-tab label="First"></mat-tab>
  <mat-tab label="Second"></mat-tab>
  <mat-tab label="Third"></mat-tab>
</mat-tab-group>

<!--see that now I use "indexOld", not "index"
    when the animation is done, you equal indexOld to index-->

<div [style.display]="indexOld!=0?'none':null" [@flyInOut]="index" (@flyInOut.done)="indexOld=index">
  Content 1
</div>
<div [style.display]="indexOld!=1?'none':null" [@flyInOut]="index" (@flyInOut.done)="indexOld=index">
Content 2
</div>
<div [style.display]="indexOld!=2?'none':null" [@flyInOut]="index" (@flyInOut.done)="indexOld=index">
Content 3
</div>

查看堆栈闪电战

注意:实际上它不是“精确”到 mat-tab 中的动画,可以随意更改动画以使其更接近

更新“模拟”mat-tab 动画的动画

我们需要一次看到两个“选项卡”,所以我们需要“包装”一个 div 中的选项卡,位置相对,并使位置绝对。这使我们需要知道选项卡的“高度”。所以我们将使用“可见性”而不是“显示”,但首先我们要定义四个动画

  animations: [
    trigger('flyInOut', [
      transition('*=>inmore', [
        style({ transform: 'translateX(100%)' }), //start in
        animate(200)
      ]),
      transition('*=>inless', [
        style({ transform: 'translateX(-100%)' }), //start in
        animate(200)
      ]),
      transition('*=>outless', [
        animate(200, style({ transform: 'translateX(100%)' })) //end in
      ]),
      transition('*=>outmore', [
        animate(200, style({ transform: 'translateX(-100%)' })) //end in
      ])
    ])
  ]

如果“i”是 index 或 indexOld,我们将看到选项卡,为了获得“动画”,我们将使用一个函数

  getAnimation(i:number,indexOld:number,index:number)
  {
    const from=(i==index)?'in':(i==indexOld)?'out':null
    if (from && indexOld!=index)
        return from+(indexOld>index?'less':'more')
    return null
  }

和.html之类的

<div class="wrapper" [style.height]="maxHeigth">
  <div #tab [style.visibility]="index!=0 && indexOld!=0?'hidden':null" [@flyInOut]="getAnimation(0,indexOld,index)"
    (@flyInOut.done)="indexOld=index">
    Content 1
  </div>
  <div #tab [style.visibility]="index!=1 && indexOld!=1?'hidden':null" [@flyInOut]="getAnimation(1,indexOld,index)"
    (@flyInOut.done)="indexOld=index">
    Content 2
  </div>
  <div #tab [style.visibility]="index!=2 && indexOld!=2?'hidden':null" [@flyInOut]="getAnimation(2,indexOld,index)"
    (@flyInOut.done)="indexOld=index">
    Content 3
  </div>
</div>

看到包装类表明

.wrapper
{
  position:relative;
  width:100%;
}
.wrapper>div
{
  position:absolute;
  width:100%;
}

最后一步是知道“maxHeigth”,因此,我们将使用 viewChildren 获取“选项卡”,并在 setTimeout 中包含的 ngAfterViewInit 中,获取 maxHeigth

  maxHeigth:string;
  @ViewChildren('tab') tabs:QueryList<ElementRef>

  ngAfterViewInit()
  {
    setTimeout(()=>{
    this.maxHeigth=this.tabs.map(x=>x.nativeElement.getBoundingClientRect().height)
                 .reduce((a,b)=>a>b?a:b,0)+'px'
    })
  }

你可以看到最后的 stackblitz


推荐阅读