【问题标题】:animate header with Angular 5使用 Angular 5 动画标题
【发布时间】:2019-01-14 14:03:42
【问题描述】:

我正在掌握角度动画,并且我正在尝试制作一个可以正确动画的标题。 我一直在关注本教程:

https://netbasal.com/reactive-sticky-header-in-angular-12dbffb3f1d3

这正在帮助我创建我的标题,但我不希望它完全按照他们正在做的事情,这就是我需要一些帮助的原因。 首先,向下滚动页面时;我不希望整个标题消失。相反,我希望它缩小到 10px 左右;当我向上滚动时,我希望它转到 60px; 我已将动画更改为:

trigger('toggle', [
  state(
    VisibilityState.Hidden,
    style({ opacity: 1, height: '10px' })
  ),
  state(
    VisibilityState.Visible,
    style({ opacity: 1, height: '60px' })
  ),
  transition('* => *', animate('200ms ease-in'))
])

它的工作范围很广。 我的模板中有一些内容在标题出现时不会缩小。 我的标题组件的 CSS 如下所示:

:host {
  position: fixed;
  top: 0;
  width: 100%;
  text-align: center; // TODO: only for testing, remove later
  background-color: indigo; // TODO: only for testing, remove later
}

HTML 看起来像这样:

<div class="header">
  <p>This is the header</p>
</div>

所以,这个问题的第一部分是,当菜单被压缩时,我如何使内容(无论是什么)隐藏?我相信这很容易:)

第二部分,我想添加一个新的事件/动画。当您将鼠标悬停在压缩形式的菜单上时,我希望它扩展为原始大小(就像您向上滚动页面一样)。 这对我来说很难,如果你能给我任何帮助,我将不胜感激。


* 更新 *

我设法让第二部分工作。 我将我的 HTML 更改为:

<div class="header" (mouseenter) ="mouseEnter() "  (mouseleave) ="mouseLeave()">
  <p>This is the header</p>
</div>

并为组件添加了一个新属性和两个新方法:

private wasVisible = this.isVisible;

mouseEnter() {
  this.wasVisible = this.isVisible === true;
  this.isVisible = true;
}

mouseLeave() {
  this.isVisible = this.wasVisible === true;
}

所以,当我悬停组件时,如果它已经可见,它将保持这种状态,当我离开时,它将重置为我进入组件之前的样子。 如果组件被压缩,它将解压缩它,当我们移出时,它会将其恢复为压缩状态。

现在我只需要弄清楚如何对内容进行排序。

【问题讨论】:

  • 你是如何将动画连接到标题的?应该有 [@toggle]="state" 之类的东西。
  • 你可以在我给出的那个链接中看到它;它是组件代码的一部分

标签: css angular animation


【解决方案1】:

所以,我能想到的唯一方法就是对元素应用一个类。所以我修改了我的切换方法:

@HostBinding('@toggle')
get toggle(): VisibilityState {
  if (this.isVisible) {
    this.renderer.removeClass(this.element.nativeElement, 'collapsed');
  }
  else {
    this.renderer.addClass(this.element.nativeElement, 'collapsed');
  }
  return this.isVisible ? VisibilityState.Visible : VisibilityState.Hidden;
}

这让我可以像这样添加修改组件的 CSS:

:host {
    position: fixed;
    top: 0;
    width: 100%;
    height: 60px;
    text-align: center; // TODO: only for testing, remove later
    background-color: indigo; // TODO: only for testing, remove later
    .header {
        visibility: visible;
        opacity: 1;
        transition: visibility .2s, opacity .2s linear;
    }
    &.collapsed .header {
        visibility: hidden;
        opacity: 0;
    }
}

现在,我不确定 CSS 是否会像 Angular 动画一样流畅地渲染,但这是我迄今为止找到的唯一解决方案。


作为参考,这里是整个组件:

import { Component, AfterViewInit, HostBinding, HostListener, ElementRef, Renderer2 } from '@angular/core';
import { animate, state, style, transition, trigger } from '@angular/animations';
import { distinctUntilChanged, filter, map, pairwise, share, throttleTime } from 'rxjs/operators';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/fromEvent';

enum VisibilityState {
  Visible = 'visible',
  Hidden = 'hidden'
}

enum Direction {
  Up = 'Up',
  Down = 'Down'
}

@Component({
  selector: 'piiick-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.scss'],
  animations: [
    trigger('toggle', [
      state(
        VisibilityState.Hidden,
        style({ height: '10px' })
      ),
      state(
        VisibilityState.Visible,
        style("*")
      ),  
      transition('* => *', animate('200ms ease-in'))
    ])
  ]
})
export class HeaderComponent implements AfterViewInit {
  private isVisible = true;
  private wasVisible = this.isVisible;

  constructor(private renderer: Renderer2, private element: ElementRef) { }

  @HostBinding('@toggle')
  get toggle(): VisibilityState {
    if (this.isVisible) {
      this.renderer.removeClass(this.element.nativeElement, 'collapsed');
    }
    else {
      this.renderer.addClass(this.element.nativeElement, 'collapsed');
    }
    return this.isVisible ? VisibilityState.Visible : VisibilityState.Hidden;
  }

  @HostListener('mouseenter')
  mouseEnter() {
    this.wasVisible = this.isVisible === true;
    this.isVisible = true;
  }

  @HostListener('mouseleave')
  mouseLeave() {
    this.isVisible = this.wasVisible === true;
  }

  ngAfterViewInit() {
    const scroll$ = Observable.fromEvent(window, 'scroll').pipe(
      throttleTime(10),
      map(() => window.pageYOffset),
      pairwise(),
      map(([y1, y2]): Direction => (y2 < y1 ? Direction.Up : Direction.Down)),
      distinctUntilChanged(),
      share()
    );

    const scrollUp$ = scroll$.pipe(
      filter(direction => direction === Direction.Up)
    );

    const scrollDown = scroll$.pipe(
      filter(direction => direction === Direction.Down)
    );

    scrollUp$.subscribe(() => (this.isVisible = true));
    scrollDown.subscribe(() => (this.isVisible = false));
  }
}

【讨论】:

    【解决方案2】:

    隐藏内容:

    将成员变量isVisible设为public,以便您可以在视图中使用它,然后使用*ngIf="isVisible"隐藏内容。

    悬停:

    在组件中添加@HostListener("mouseenter")@HostListener("mouseleave")两个方法,如下实现:

    @HostListener("mouseenter")
    onMouseEnter() {
      this.isVisible = true;
    }
    
    @HostListener("mouseleave")
    onMouseLeave() {
      this.isVisible = false;
    }
    

    【讨论】:

    • 另外,那不应该是@HostListener吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-06
    • 2018-10-05
    • 1970-01-01
    相关资源
    最近更新 更多