3

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

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

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

现实生活中的例子

我的应用程序抽屉使用此代码制作动画

<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 上下文中执行此操作的方法?

谢谢!

4

3 回答 3

5

无法基于 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'))

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

于 2017-09-18T13:59:56.350 回答
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

MatDialog 内的动画不起作用

祝你好运✌</p>

于 2019-04-08T13:01:15.590 回答
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)
   }
}
于 2018-05-18T18:43:24.213 回答