【问题标题】:Angular 4 component responsive animationsAngular 4 组件响应式动画
【发布时间】:2020-06-30 16:59:30
【问题描述】:

我正在开发一个 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 上下文中执行此操作的方法?

谢谢!

【问题讨论】:

    标签: angular media-queries angular-animations web-animations


    【解决方案1】:

    没有办法基于 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'))
    

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

    【讨论】:

    • 你能举个例子来说明你如何使用这个服务来配置组件的动画对象吗?
    • @neoswf 当然。请参阅我的扩展答案。
    • 首先,谢谢!喜欢您的解决方案,但我不得不说堆叠 OnResize 侦听器并不是我想对我的应用程序做的最好的事情。已经对滚动监听感到厌烦了。不喜欢,但是好像我这里不会有太多的选择......
    • 天哪,我写这篇文章的时候是不是喝醉了?它充满了错别字。无论如何,它绝对不是优雅的,但它是强大的。这是一个非常可扩展的解决方案,它允许您的“响应能力”比旧的 CSS 断点所允许的更复杂和更有能力。显然,权衡是复杂性的显着增加。我仍在争论我是否使用这个想法。
    • @neoswf 在我的调整大小监视器上,我有一个高度去抖动器。我之前用了半秒,但现在我用了一整秒,并且在用户更改屏幕尺寸后,屏幕右上角出现了一个小元素,上面写着“调整大小”,为用户提供一些信息发生了什么。
    【解决方案2】:

    不是最强大的解决方案,但如果动画的最终状态对于每个媒体查询都是相同的(例如,您要为两个项目设置动画以供查看,但希望为移动设备和桌面设备提供不同的动画),那么您可以定义初始状态在 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)
       }
    }
    

    【讨论】:

      【解决方案3】:

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

      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

      祝你好运✌

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-12-15
        • 2017-12-25
        • 2016-06-13
        • 1970-01-01
        • 2018-02-21
        • 1970-01-01
        • 2021-02-05
        相关资源
        最近更新 更多