1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

メディアクエリをangularで設定するディレクティブ

Last updated at Posted at 2019-05-02

どこかに誰か書いてそうで、意外となかったので、まとめてみたり。
(でも、まだangularよ〜わからん!な未熟者だったりするので(というか、jsが使いこなせない)、なんか微妙だったらご指摘ください。)

やりたいこと

テンプレートになんか書くことで、スクリーンサイズに応じて表示非表示を切り替える部分を切り分けたい

雰囲気
<template *mediaquery="720px以下">
720px以下で表示したい
</template>
<template *mediaquery="そうじゃないサイズで表示したい">
721px以上で表示したい
</template>

ディレクティブを定義するファイルの作成

angular cliを利用しての作成は↓

angulr-cli
ng g directive app以下ファイルパス/ディレクティブファイル名

今回はapp/directiveにディレクティブを整理した構成で、mediaqueryという名前で作成しようと思うので
ng g directive directive/mediaqueryになる。
作成すると、ファイルが作成されるとともに、app.moduleに登録される。

app.module.ts
import { MediaqueryDirective } from './directive/mediaquery.directive';

@NgModule({
  declarations: [
    AppComponent,
    ~~
    MediaqueryDirective,
  ],
  ~~
})
~~

ディレクティブの実装

利用元から、引数を受け取る

Inputoオブジェクトを利用できるようにして、利用元からの引数(?)を受け取れるようにする。

mediaquery.directive.ts
import { Directive, Input } from '@angular/core';

@Directive({
  selector: '[appMediaquery]'
})
export class MediaqueryDirective {

  @Input('appMediaquery') mediaquery: string;

  constructor() { }

}

ここで、@Input('appMediaquery') mediaquery: string;にすると、

Uncaught Error: Template parse errors:
Can't bind to 'appMediaquery' since it isn't a known property of 'div'.

というエラーが発生!ということで、注意。(まだまだわかってないまま作成しております。)

テンプレートを扱うオジェクトを追加

テンプレートにした要素を挿入するためのオブジェクトを記載。

mediaquery.directive.ts
import { Directive, Input, TemplateRef, ViewContainerRef } from '@angular/core';

@Directive({
  selector: '[appMediaquery]'
})
export class MediaqueryDirective {

  @Input() mediaquery: string;

    constructor(private templateRef: TemplateRef<any>, private viewContainer: ViewContainerRef ) {
  }

}

値を受け取って何かするための下準備

OnChangesメソッドを利用できるようにする&テンプレートを埋め込むメソッドを記入。
とりあえず、何の条件もつけずに、consoleで正しく動くか&テンプレートが表示されるかお試し。

mediaquery.directive.ts

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

~~
export class MediaqueryDirective implements OnChanges {

  ~~

  ngOnChanges() {
    console.log('abc');
    if ( this.mediaquery === 'hoge') {
      console.log('def');
      this.viewContainer.createEmbeddedView(this.templateRef);
    } else {
      console.log('ghi');
      this.viewContainer.clear();
    }
  }
}

hoge.component.html
<div *appMediaquery='hoge'>aaaaa</div>
//↑「*」はテンプレートを再利用できるものにするディレクティブの利用を表すらしい。
//ディレクティブの selector に定義してあるものを記載

条件を作る

sassのmediaquery mixinにあわわせる感じで、breakpointの変数を登録

手前味噌な参照:メディアクエリをsassで設定するmixin
https://qiita.com/niever66/items/dae7799b1ebec1881c25

mediaquery.directive.ts
export class MediaqueryDirective implements OnChanges {

  ~~

  breakpoints = {
    xs: 520,
    sm: 768,
    md: 1024,
    lg: 1366,
    xl: 1920
  };
}

渡された文字列を元に条件文を作成
※コピペで変に重複したコード記載していたので、重複箇所削除(2019.5.7)

mediaquery.directive.ts
export class MediaqueryDirective implements OnChanges {

  ~~

  ngOnChanges() {
    let operator: string;
    let pt = this.mediaquery.split(/[a-z]/);
    for ( let i = 0; i < pt.length; i++ ) {
      if( pt[i] ){
        operator = pt[i];
        break;
      }
    }

    let bp: string;
    let mq = this.mediaquery.split(operator);
    for ( let i = 0; i < mq.length; i++ ) {
      if( mq[i] ){
        bp = mq[i];
        break;
      }
    }

    switch (operator) {
      case '<':
        if (window.innerWidth < this.breakpoints[bp]) {
          this.viewContainer.createEmbeddedView(this.templateRef);
        } else {
          this.viewContainer.clear();
        }
        break;
      case '>':
        if (window.innerWidth > this.breakpoints[bp]) {
          this.viewContainer.createEmbeddedView(this.templateRef);
        } else {
          this.viewContainer.clear();
        }
        break;
      case '=':
        if (window.innerWidth === this.breakpoints[bp]) {
          this.viewContainer.createEmbeddedView(this.templateRef);
        } else {
          this.viewContainer.clear();
        }
        break;
      case '<=':
      case '=<':
        if (window.innerWidth <= this.breakpoints[bp]) {
          this.viewContainer.createEmbeddedView(this.templateRef);
        } else {
          this.viewContainer.clear();
        }
        break;
      case '>=':
      case '=>':
        if (window.innerWidth >= this.breakpoints[bp]) {
          this.viewContainer.createEmbeddedView(this.templateRef);
        } else {
          this.viewContainer.clear();
        }
        break;
      default:
        this.viewContainer.clear();
      }

  }
}

テンプレートから呼び出す

template.component.html
<div *appMediaquery="'<=sm'">smサイズより小さい時に表示</div>

とりま完成!

ところで、これだとまだ min:hoge and max:fuge 的な 間の時っていうのができませんな。

1
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?