Angular 4 个组件响应式动画

Angular 4 component responsive animations

我正在开发一个 Angular 响应式应用程序,它在移动设备上有一个抽屉。

我喜欢 Angular 中的 Web 动画 API 实现,但我找不到可以根据我的媒体查询断点配置动画的地方。

我所能找到的就是通过我的 css sheet 取消动画,但这让我开始在我的项目的不同地方传播代码,我不确定这是 angular 打算让我做的...

现实生活中的例子

我的应用程序抽屉使用这段代码来制作动画

<div class="mobile-menu" [@animateDrawer]="drawerOpened">
  <!-- Drawer's menu goes here -->
</div>

drawerOpened is a boolean that toggle when app menu button is pressed.

我的组件看起来像这样:

@Component({
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.scss'],
  animations: [
    trigger('animateDrawer', [
      state('inactive', style({
        transform: 'translate3d(-100%, 0, 0)'
      })),
      state('active', style({
        transform: 'translate3d(0, 0, 0)'
      }))
    ])
  ]
})

取消动画效果的CSS代码

.mobile-menu {
  opacity: 1 !important;
  display: flex !important;
  transform: none !important;
}

除了在我的 css 代码中操作所有内容并禁用 Desktop BreakPoint 上的 css 属性外,是否存在在 Angular 上下文中执行此操作的某种方法?

谢谢!

无法根据 CSS @Media 查询定义 JavaScript 行为。您将必须执行我所做的操作,我在其中创建了一个 Angular 外观服务,用于监视视口尺寸并根据检测到的内容向组件发送命令。然后,您可以使用 JavaScript 逻辑而不是 CSS 逻辑来控制动画和外观。

添加示例:

创建一个监视视口宽度的服务。如果视口小于 500 像素,则服务输出“移动设备”,否则,它输出“桌面设备”。

在您的组件中,声明一个触发器,我们将其称为@slide,具有多个状态。我们还将设置一个名为 stateOfYourChoosing 的私有变量,您可以将其设置为字符串。

然后,在您的模板中

<div [@slide]="stateOfYourChoosing"></div>

然后您可以选择您希望 stateOfYourChoosing 的默认状态是哪个状态,以及您希望组件如何根据组件逻辑进行转换。

因此,如果您的外观服务输出“桌面”,您的默认 stateOfYourChoosing 将是“slideOut”。

transition('slideOut => slideIn', animate('100ms ease-in'))

如果外观服务输出“mobile”,它会将 stateOfYourChoosing 设置为“mobileSlideOut”,而您的转换代码是

transition('mobileSlideOut => mobileSlideIn', animate('100ms ease-in'))

然后您可以通过控制触发器的状态来控制动画模块中的所有响应动画。

不是最稳健的解决方案,但如果每个媒体查询的动画结束状态都相同(例如,您正在为两个项目设置动画以供查看,但希望移动设备和桌面使用不同的动画),那么您可以定义css 中的初始状态使用媒体查询,在 angular 组件中使用 '*' 作为目标 css 属性初始状态

trigger('animation', [
  state('out, none, void', style({
    transform: '*'
  })),
  state('in', style({
    transform: 'translate3d(0, 0, 0)'
  })),
  transition('below => in, none => in', animate(`300ms ease`))
])

然后在 css

.class {
  //animate from bottom on mobile
  transform: translate3d(0, -100%, 0);

   @media all and (min-width: 920px) {
     //animate from left on desktop
     transform: translate3d(-100%, 0, 0)
   }
}

一种方法是在运行时创建动画,而不是在组件装饰器中声明它们。

  1. 创建将由组件使用的服务。
  2. 创建一个接收动画配置的新方法。
  3. 检测window尺寸。
  4. 构建并return动画。

看起来有点像这样(以下代码未经测试,只是一个示例):

export interface MediaQueryStyle
{
    minWidth: number;
    initialStyle: any; // Style object to apply before animation
    endStyle: any;     // Style object to apply after animation
}

export interface MediaQueryAnimationConfig
{
    element: ElementRef;
    mediaStyles: MediaQueryStyle[];
    duration?: number | string;

    ... // Whatever you need to create your animation 
}

服务:

@Injectable({
    providedIn: 'root'
})
export class MediaQueryAnimationService
{
    constructor(private builder: AnimationBuilder) { }

    public create(config: MediaQueryAnimationConfig): AnimationPlayer
    {
        // Read animation configuration
        const duration = config.duration || 1000;
        const mediaStyle = this.findMediaStyle(config.styles);

        // Build the animation logic (add here any other operation, e.g. query)
        const animation = this.builder.build([
            style(mediaStyle.initialStyle),
            animate(duration, style(mediaStyle.endStyle)
        ]);

        return animation.create(config.element);
    }

    private findMediaStyle(styles: MediaQueryStyle[])
    {
        const viewWidth = window.innerWidth;

        // Some logic to scan the array and return the style that complies with `viewWidth`
        return styles.find(style => ...);
    }
}

在你的组件中:

<something ... #someElement></something>
@Component({
    selector: 'something',
    templateUrl: './something.component.html',
    styleUrls: ['./something.component.scss']
})
export class SomethingComponent implements OnInit
{
    @ViewChild('someElement')
    private elementRef: ElementRef;

    constructor(private mqAnimation: MediaQueryAnimationService) { }

    ngOnInit() { ... }

    public onSomeEvent()
    {
        const player = mqAnimation.create({ element: elementRef.element, minWidth: ... });

        player.onDone(player.destroy);

        player.play();
    }
}

有用的阅读材料和示例:

https://angular.io/api/animations/AnimationBuilder

https://stackblitz.com/edit/angular-animation-builder

祝你好运✌