在Angular中使用正确的CSS媒体查询

ny6fqffe  于 2023-06-25  发布在  Angular
关注(0)|答案(5)|浏览(142)

我读到在Angular中使用CSS隐藏元素来隐藏这样的元素是一个非常糟糕的做法:

.container{
  background-color : powderblue;
  height : 50px;
  width : 100%
}

@media (max-width: 400px){
    .container{
        display: none;
    }

}
<div class="container"></div>

我知道Angular显示或隐藏元素的方式是使用*ngIf指令。

提问

如何让* ngIf以“Angular方式”对媒体查询做出React?

1yjd4xko

1yjd4xko1#

可以使用angular/breakpoints-angular-cdk
按照以下步骤操作
在终端上

npm install @angular/cdk

然后导入布局模块并将其添加到NgModule的导入列表中

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { LayoutModule } from '@angular/cdk/layout';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
  AppComponent
],
imports: [
    BrowserModule,
    LayoutModule
],
providers: [],
bootstrap: [AppComponent]
})

在您可以在组件中使用它之后,只需从@angular/cdk/layout导入这些类

import { Component, OnInit } from '@angular/core';
import { BreakpointObserver, BreakpointState } from '@angular/cdk/layout';

@Component({ ... })
export class AppComponent implements OnInit {
  public showContainer: boolean;
  constructor(public breakpointObserver: BreakpointObserver) {}

  ngOnInit() {
    this.breakpointObserver
      .observe(['(min-width: 400px)'])
      .subscribe((state: BreakpointState) => {
        if (state.matches) {
          this.showContainer = true;
        } else {
          this.showContainer = false;
        }
      });
  }
}

检查the docs,它是一个简单的API
!!注意新的Angular 版本,有一个更好的方法来做!!

更新如果您使用的是较新版本的Angular,则有一个常量可帮助识别屏幕大小

import { Component, OnInit } from '@angular/core';
import { BreakpointObserver, BreakpointState, Breakpoints } from '@angular/cdk/layout';
// NEW Breakpoints CONSTANT
@Component({ ... })
export class AppComponent implements OnInit {
  public showContainerInTablet: boolean;
  public showContainerInHandset: boolean;
  constructor(public breakpointObserver: BreakpointObserver) {}

  ngOnInit() {
    this.breakpointObserver
      .observe([
        Breakpoints.TabletPortrait,
        Breakpoints.HandsetLandscape
      ])
      .subscribe((state ) => {
        const breakpoints = state.breakpoints;
        this.showContainerInHandset = false;
        this.showContainerInTablet = false;
        if (breakpoints[Breakpoints.TabletPortrait]) {
         this.showContainerInTablet = true;
         console.log("screens matches TabletPortrait");
        }
        else if (breakpoints[Breakpoints.HandsetLandscape]) {
         this.showContainerInHandset = true;
         console.log("screens matches HandsetLandscape");
       } 
      });
  }
}

查看angular website教程

rta7y2nd

rta7y2nd2#

Angular Flex布局是更好的解决方案。你不需要媒体查询,它有特殊的响应功能,例如显示和隐藏
fxShow:这个标记指定是否应该显示(或不显示)其宿主元素

<div fxShow [fxShow.xs]="isVisibleOnMobile()"></div>

fxHide:此标记指定是否不应显示其宿主元素

<div fxHide [fxHide.gt-sm]="isVisibleOnDesktop()"></div>

不需要写大量的css,它与角材料非常兼容。https://github.com/angular/flex-layout

4szc88ey

4szc88ey3#

我想出了下面的基类,并发现它工作得很好。

import { HostBinding, OnDestroy, OnInit } from '@angular/core';
import { MediaObserver } from '@angular/flex-layout';
import { Subscription } from 'rxjs';

export class MediaQueryClassBaseComponent implements OnInit, OnDestroy {
    @HostBinding('class.xl') private xl: boolean;
    @HostBinding('class.lg') private lg: boolean;
    @HostBinding('class.md') private md: boolean;
    @HostBinding('class.sm') private sm: boolean;
    @HostBinding('class.xs') private xs: boolean;

    private mediaObserverSubscription: Subscription | undefined = undefined;

    constructor(protected readonly mediaObserver: MediaObserver) {}

    ngOnInit(): void {
        if (this.mediaObserverSubscription)
            return;
        this.mediaObserverSubscription = this.mediaObserver.media$.subscribe(x => {
            this.xl = x.mqAlias == 'xl';
            this.lg = x.mqAlias == 'lg';
            this.md = x.mqAlias == 'md';
            this.sm = x.mqAlias == 'sm';
            this.xs = x.mqAlias == 'xs';
        });
    }

    ngOnDestroy(): void {
        if (!this.mediaObserverSubscription)
            return;
        this.mediaObserverSubscription.unsubscribe();
        this.mediaObserverSubscription = undefined;
    }
}

如果从该类继承(扩展)组件,组件的host元素将添加一个类,其中包含媒体查询别名。比如...

<app-search-bar class="some-class" _nghost-c5 ...>

。。。就会变成。。

<app-search-bar class="some-class lg" _nghost-c5 ...>

注意添加的媒体查询别名“lg”,它将根据窗口大小而改变。这使得通过在组件的SCSS文件中 Package 特定于大小的样式,可以轻松地将响应样式添加到每个介质大小。像这样...

:host-context(.sm, .md) { // styles specific to both sm and md media sizes
    .header {
        padding: 6px;
        width: 420px;
    }
}

:host-context(.lg, .xl) { // styles specific to both lg and xl media sizes
    .header {
        padding: 10px;
        width: 640px;
    }
}

我已经把完整的文件放在我的gist https://gist.github.com/NickStrupat/b80bda11daeea06a1a67d2d9c41d4993

yptwkmov

yptwkmov4#

检查这里,它的分叉解决方案发现在互联网上的某个地方与我的定制,但它为我工作(不仅隐藏元素与显示:无,但删除如果从DOM -像 *ngIf工程)

import {
        Input,
        Directive,
        TemplateRef,
        ViewContainerRef,
        OnDestroy,
        ChangeDetectorRef
    } from '@angular/core';

    /**
     * How to use this directive?
     *
     * ```
     * 
     *     Div element will exist only when media query matches, and created/destroyed when the viewport size changes.
     * 
     * ```
     */
    @Directive({
        selector: '[mqIf]'
    })
    export class MqIfDirective implements OnDestroy {
        private prevCondition: boolean = null;
        i = 0;

        private mql: MediaQueryList;
        private mqlListener: (mql: MediaQueryList) => void;   // reference kept for cleaning up in ngOnDestroy()
        constructor(private viewContainer: ViewContainerRef,
                    private templateRef: TemplateRef,
                    private ref: ChangeDetectorRef) {
        }

        /**
         * Called whenever the media query input value changes.
         */
        @Input()
        set mqIf(newMediaQuery: string) {
            if (!this.mql) {
                this.mql = window.matchMedia(newMediaQuery);

                /* Register for future events */
                this.mqlListener = (mq) => {
                    this.onMediaMatchChange(mq.matches);
                };
                this.mql.addListener(this.mqlListener);
            }

            this.onMediaMatchChange(this.mql.matches);
        }

        ngOnDestroy() {
            this.mql.removeListener(this.mqlListener);
            this.mql = this.mqlListener = null;
        }

        private onMediaMatchChange(matches: boolean) {
            if (matches && !this.prevCondition) {
                this.prevCondition = true;
                this.viewContainer.createEmbeddedView(this.templateRef);
            } else if (!matches && this.prevCondition) {
                this.prevCondition = false;
                this.viewContainer.clear();
            }

            /**
             * Infinitive loop when we fire detectChanges during initialization
             * (first run on that func)
             */
            if (this.i > 0) {
                this.ref.detectChanges();
            }
            else
                this.i++;
        }
    }

See here

nkkqxpd9

nkkqxpd95#

.container{
  background-color : powderblue;
  height : 50px;
  width : 100%
}

@media (max-width: 400px){
    .container{
        display: flex;
    }

}
<div class="container"></div>

相关问题