【问题标题】:Angular: Best way to do media queriesAngular:进行媒体查询的最佳方式
【发布时间】:2021-01-09 05:58:39
【问题描述】:

目前我使用 NgZone 来运行媒体查询。我很好奇这是否是最好的方法。

import { NgZone } from '@angular/core';

const SMALL_WIDTH_BREAKPOINT = 840;

export class AppComponent implements OnInit {
  private mediaMatcher: MediaQueryList = matchMedia(`(max-width: ${SMALL_WIDTH_BREAKPOINT}px)`);
  constructor (
    zone: NgZone,
  ) {
    this.mediaMatcher.addListener(mql => zone.run(() => this.mediaMatcher = mql));
  }

  isScreenSmall(): boolean {
    return this.mediaMatcher.matches;
  }
}

【问题讨论】:

    标签: angular media-queries responsive


    【解决方案1】:

    我意识到这是一个非常古老的问题,但我在尝试在我们的 Angular 9 应用程序中做同样的事情时遇到了这个问题。

    如果您也想将 zone.js webapis-media-query 文件导入您的应用程序,您建议的方法看起来不错,尽管它可以在不使用 zone.run 的情况下完成。

    import 'zone.js/dist/webapis-media-query'(see zone.js non standard apis)

    我在尝试使用 matchMedia('...').addListener 将新断点推送到 Rxjs 主题时遇到了这个问题。我在组件中订阅了该主题,并且当值更改时它没有触发模板中的更改检测。更新模板大约需要 5 秒(由于区域的定期更新)。导入webapis-media-query 文件为我解决了这个问题。

    如果您不需要支持 IE 或 Safari(在撰写本文时至少为 12.1.2),您可以使用window.matchMedia('max-width: 648px').addEventListener('change', callback),zone.js 似乎无需导入该库即可修补。

    我们的来源:

    import 'zone.js/dist/webapis-media-query'
    
    interface BreakpointQuery {
      query: string,
      breakpoint: ScreenSize
    }
    
    type MediaQueryListListener = (event: MediaQueryListEvent) => void
    
    export enum ScreenSize { Small, Medium, Large }
    
    const SMALL = 640
    const MEDIUM = 1024
    const queries: BreakpointQuery[] = [
      { query: `(max-width: ${SMALL}px)`, breakpoint: ScreenSize.Small },
      { query: `(min-width: ${SMALL + 1}px) and (max-width: ${MEDIUM}px)`, breakpoint: ScreenSize.Medium },
      { query: `(min-width: ${MEDIUM + 1}px)`, breakpoint: ScreenSize.Large }
    ]
    
    @Injectable({
      providedIn: 'root'
    })
    export class ScreenSizeService {
      size: Observable<ScreenSize>
    
      private subject: BehaviorSubject<ScreenSize>
    
      constructor (
        private readonly windowRefService: WindowRefService
      ) {
        this.setupSizeObservable()
        this.setupMediaQueries()
      }
    
      private setupSizeObservable (): void {
        this.subject = new BehaviorSubject<ScreenSize>(this.currentSize())
        this.size = this.subject.asObservable()
      }
    
      private setupMediaQueries (): void {
        queries.forEach(breakpointQuery => {
          // @see False deprecation of addListener https://github.com/microsoft/TypeScript/issues/32210
          this.windowRefService.matchMedia(breakpointQuery.query)
            .addListener(this.mediaChange(breakpointQuery.breakpoint))
        })
      }
    
      private mediaChange (size: ScreenSize): MediaQueryListListener {
        return (event: any) => {
          if (event.matches) {
            this.subject.next(size)
          }
        }
      }
    
      private currentSize (): ScreenSize {
        const current = queries.find(breakpointQuery => {
          return this.windowRefService.matchMedia(breakpointQuery.query).matches
        })
        return current!.breakpoint
      }
    }
    

    【讨论】:

    • 这是您添加的一项很棒的服务@Benno。我将使用这个window.service stackblitz.com/edit/…,但也想问一下你在哪里得到MediaQueryListListener 的打字?
    • @BenRacicot 我们将它添加到我们的 repos 自定义类型中,因为我相信它在 3.1 中已从 typescript 中删除。这是我们的类型:type MediaQueryListListener = (event: any) =&gt; void 但我认为我们现在可以实际使用它:type MediaQueryListListener = (event: MediaQueryListEvent) =&gt; void
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-19
    • 2016-11-02
    • 2016-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-18
    相关资源
    最近更新 更多