我正在开发一个Angular响应式应用程序,它在移动设备上有一个抽屉。
我喜欢Angular中的Web动画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上下文中是否存在某种方式?
谢谢!
答案 0 :(得分:4)
无法基于CSS @Media查询定义JavaScript行为。你将不得不做我所做的,在那里我创建了一个Angular外观服务,它监视视口尺寸并根据检测到的内容向组件发送命令。然后,您可以使用JavaScript逻辑而不是CSS逻辑来控制动画和外观。
添加示例:
创建一个监视视口宽度的服务。如果视口小于,例如500px,则服务输出&#34; mobile,&#34;否则,它输出&#34;桌面。&#34;
在你的组件中,声明一个触发器,我们将其称为@slide,具有多个状态。我们还将设置一个名为stateOfYourChoosing的私有变量,您可以将其设置为字符串。
然后,在您的模板中
<div [@slide]="stateOfYourChoosing"></div>
然后,您可以选择stateOfYourChoosing的默认状态,以及您希望组件根据组件逻辑进行转换的方式。
因此,如果您的外观服务输出&#34;桌面,&#34;你的默认stateOfYourChoosing将是&#34; slideOut。&#34;
transition('slideOut => slideIn', animate('100ms ease-in'))
如果外观服务输出&#34;移动,&#34;它将stateOfYourChoosing设置为&#34; mobileSlideOut,&#34;而你的转换代码是
transition('mobileSlideOut => mobileSlideIn', animate('100ms ease-in'))
然后,您可以通过控制触发器的状态来控制动画模块中的所有响应动画。
答案 1 :(得分:1)
One way would be to create your animation on runtime instead of declaring them in your component decorator.
It would look somewhat like this (The following code is not tested and is simply an example):
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
}
The service:
@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 => ...);
}
}
In your component:
<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();
}
}
Useful reading and examples:
https://angular.io/api/animations/AnimationBuilder
https://stackblitz.com/edit/angular-animation-builder
Animation inside of MatDialog is not working
Good luck ✌
答案 2 :(得分:0)
不是最强大的解决方案,但如果动画的最终状态对于每个媒体查询都是相同的(例如,您要将两个项目设置为动画,但想要移动和桌面的不同动画),那么您可以定义初始css中的状态使用媒体查询和角度组件使用&#39; *&#39;对于目标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)
}
}