用Angular 5设置动画标题

时间:2018-08-07 13:01:21

标签: css angular animation

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

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

这可以帮助我创建标题,但是我不希望它完全执行他们正在做的事情,这就是为什么我需要一些帮助。 首先,向下滚动页面时;我不希望整个标题消失。相反,我希望它缩小到10px左右;当我向上滚动时,我希望它达到60像素; 我将动画更改为此:

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>

并向该组件添加了一个新属性和2个新方法:

private wasVisible = this.isVisible;

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

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

因此,当我将鼠标悬停在组件上时,如果它已经可见,它将保持该状态;当我离开组件时,它将重置为进入组件之前的状态。 如果压缩了该组件,它将对其进行解压缩,而当我们移出该组件时,它将使其恢复压缩状态。

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

2 个答案:

答案 0 :(得分:1)

隐藏内容:

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

悬停:

向组件添加两个带有@HostListener("mouseenter")@HostListener("mouseleave")的方法,像这样实现它们:

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

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

答案 1 :(得分:0)

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

@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));
  }
}