どこかに誰か書いてそうで、意外となかったので、まとめてみたり。
(でも、まだangularよ〜わからん!な未熟者だったりするので(というか、jsが使いこなせない)、なんか微妙だったらご指摘ください。)
やりたいこと
テンプレートになんか書くことで、スクリーンサイズに応じて表示非表示を切り替える部分を切り分けたい
<template *mediaquery="720px以下">
720px以下で表示したい
</template>
<template *mediaquery="そうじゃないサイズで表示したい">
721px以上で表示したい
</template>
ディレクティブを定義するファイルの作成
angular cliを利用しての作成は↓
ng g directive app以下ファイルパス/ディレクティブファイル名
今回はapp/directive
にディレクティブを整理した構成で、mediaquery
という名前で作成しようと思うので
ng g directive directive/mediaquery
になる。
作成すると、ファイルが作成されるとともに、app.moduleに登録される。
import { MediaqueryDirective } from './directive/mediaquery.directive';
@NgModule({
declarations: [
AppComponent,
~略~
MediaqueryDirective,
],
~略~
})
~略~
ディレクティブの実装
利用元から、引数を受け取る
Inputoオブジェクトを利用できるようにして、利用元からの引数(?)を受け取れるようにする。
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'.
というエラーが発生!ということで、注意。(まだまだわかってないまま作成しております。)
テンプレートを扱うオジェクトを追加
テンプレートにした要素を挿入するためのオブジェクトを記載。
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で正しく動くか&テンプレートが表示されるかお試し。
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();
}
}
}
<div *appMediaquery='hoge'>aaaaa</div>
//↑「*」はテンプレートを再利用できるものにするディレクティブの利用を表すらしい。
//ディレクティブの selector に定義してあるものを記載
条件を作る
sassのmediaquery mixinにあわわせる感じで、breakpointの変数を登録
手前味噌な参照:メディアクエリをsassで設定するmixin
https://qiita.com/niever66/items/dae7799b1ebec1881c25
export class MediaqueryDirective implements OnChanges {
~略~
breakpoints = {
xs: 520,
sm: 768,
md: 1024,
lg: 1366,
xl: 1920
};
}
渡された文字列を元に条件文を作成
※コピペで変に重複したコード記載していたので、重複箇所削除(2019.5.7)
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();
}
}
}
テンプレートから呼び出す
<div *appMediaquery="'<=sm'">smサイズより小さい時に表示</div>
とりま完成!
ところで、これだとまだ min:hoge and max:fuge 的な 間の時っていうのができませんな。