角度4分量响应动画

问题描述 投票:1回答:3

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

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

我所能找到的就是通过我的css表取消动画,但这让我开始在我的项目中的不同位置传播代码,而且我不确定这是我想做的角度......

真实的例子

我的应用程序抽屉使用此代码进行动画处理

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

drawerOpened是一个布尔值,可在按下应用程序菜单按钮时切换。

我的组件看起来像这样:

@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上下文中是否存在某种方式?

谢谢!

angular media-queries angular-animations web-animations
3个回答
4
投票

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

添加示例:

创建一个监视视口宽度的服务。如果视口小于500px,则服务输出“mobile”,否则输出“desktop”。

在你的组件中,声明一个触发器,我们称之为@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'))

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


1
投票

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

  1. 创建将由组件使用的服务。
  2. 创建一个接收动画配置的新方法。
  3. 检测窗口大小。
  4. 构建并返回动画。

看起来有点像这样(下面的代码没有经过测试,只是一个例子):

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

Animation inside of MatDialog is not working

祝你好运✌


0
投票

不是最强大的解决方案,但如果动画的最终状态对于每个媒体查询都是相同的(例如,您要将两个项目设置为动画,但需要为移动设备和桌面设置不同的动画),那么您可以在css中定义初始状态使用媒体查询并在角度组件中使用'*'作为目标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)
   }
}
© www.soinside.com 2019 - 2024. All rights reserved.