18

Я пробираюсь в Angular2. Моя цель - создать отзывчивое приложение, которое загружает разные компоненты в ответ на различные медиа-запросы для ширины устройства. Мой рабочий пример имеет MatchMediaService:Как сделать отзывчивые компоненты в Angular2

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

@Injectable() 
export class MatchMediaService 
{ 
    constructor() 
    { 

    } 

    rules = 
    { 
     print: "print", 
     screen: "screen", 
     phone: '(max-width: 767px)', 
     tablet: '(min-width: 768px) and (max-width: 1024px)', 
     desktop: '(min-width: 1025px)', 
     portrait: '(orientation: portrait)', 
     landscape: '(orientation: landscape)', 
     retina: '(-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi)' 
    }; 

    Check = function (mq) 
    { 
     if (!mq) 
     { 
      return; 
     } 

     return window.matchMedia(mq).matches; 
    }; 

/********************************************** 
    METHODS FOR CHECKING TYPE 
**********************************************/ 
    IsPhone() 
    { 
     return window.matchMedia(this.rules.phone).matches; 
    }; 

    IsTablet = function() 
    { 
     return window.matchMedia(this.rules.tablet).matches; 
    }; 

    IsDesktop = function() 
    { 
     return window.matchMedia(this.rules.desktop).matches; 
    }; 

    IsPortrait = function() 
    { 
     return window.matchMedia(this.rules.portrait).matches; 
    }; 

    IsLandscape = function() 
    { 
     return window.matchMedia(this.rules.landscape).matches; 
    }; 

    IsRetina = function() 
    { 
     return window.matchMedia(this.rules.retina).matches; 
    }; 


/********************************************** 
    EVENT LISTENERS BY TYPE 
**********************************************/  
    OnPhone(callBack) 
    { 
     if (typeof callBack === 'function') 
     { 
      var mql: MediaQueryList = window.matchMedia(this.rules.phone); 

      mql.addListener((mql: MediaQueryList) => 
      { 
       if (mql.matches) 
       { 
        callBack(mql); 
       } 
      }); 
     } 
    }; 

    OnTablet(callBack) 
    { 
     if (typeof callBack === 'function') 
     { 
      var mql: MediaQueryList = window.matchMedia(this.rules.tablet); 

      mql.addListener((mql: MediaQueryList) => 
      { 
       if (mql.matches) 
       { 
        callBack(mql); 
       } 
      }); 
     } 
    }; 

    OnDesktop(callBack) 
    { 
     if (typeof callBack === 'function') 
     { 
      var mql: MediaQueryList = window.matchMedia(this.rules.desktop); 

      mql.addListener((mql: MediaQueryList) => 
      { 
       if (mql.matches) 
       { 
        callBack(mql); 
       } 
      }); 
     } 
    }; 

    OnPortrait(callBack) 
    { 
     if (typeof callBack === 'function') 
     { 
      var mql: MediaQueryList = window.matchMedia(this.rules.portrait); 

      mql.addListener((mql: MediaQueryList) => 
      { 
       if (mql.matches) 
       { 
        callBack(mql); 
       } 
      }); 
     } 
    }; 

    OnLandscape(callBack) 
    { 
     if (typeof callBack === 'function') 
     { 
      var mql: MediaQueryList = window.matchMedia(this.rules.landscape); 

      mql.addListener((mql: MediaQueryList) => 
      { 
       if (mql.matches) 
       { 
        callBack(mql); 
       } 
      }); 
     } 
    }; 
} 

Затем внутри компоненты «родительскую» (HomeComponent), я использую MatchMediaService, чтобы определить, какой компонент ребенка (HomeMobileComponent или HomeDesktopComponent) для загрузки в зависимости от того, что MatchMediaService возвращается, а также слушатель события что огонь, когда браузер изменяет размеры с помощью различных размеров:

import { Component, OnInit, NgZone } from '@angular/core'; 
import { MatchMediaService } from '../shared/services/match-media.service'; 
import { HomeMobileComponent } from './home-mobile.component'; 
import { HomeDesktopComponent } from './home-desktop.component'; 

@Component({ 
    moduleId: module.id, 
    selector: 'home.component', 
    templateUrl: 'home.component.html', 
    providers: [ MatchMediaService ], 
    directives: [ HomeMobileComponent, HomeDesktopComponent ] 
}) 
export class HomeComponent implements OnInit 
{ 
    IsMobile: Boolean = false; 
    IsDesktop: Boolean = false; 

    constructor(
     private matchMediaService: MatchMediaService, 
     private zone: NgZone   
    ) 
    { 
     //GET INITIAL VALUE BASED ON DEVICE WIDTHS AT TIME THE APP RENDERS 
     this.IsMobile = (this.matchMediaService.IsPhone() || this.matchMediaService.IsTablet()); 
     this.IsDesktop = (this.matchMediaService.IsDesktop()); 

     var that = this; 


     /*--------------------------------------------------- 
     TAP INTO LISTENERS FOR WHEN DEVICE WIDTH CHANGES 
     ---------------------------------------------------*/ 

     this.matchMediaService.OnPhone(
      function (mediaQueryList: MediaQueryList) 
      { 
       that.ShowMobile(); 
      } 
     ); 

     this.matchMediaService.OnTablet(
      function (mediaQueryList: MediaQueryList) 
      { 
       that.ShowMobile(); 
      } 
     ); 

     this.matchMediaService.OnDesktop(
      function (mediaQueryList: MediaQueryList) 
      { 
       that.ShowDesktop(); 
      } 
     ); 
    } 

    ngOnInit() 
    { 

    } 

    ShowMobile() 
    { 
     this.zone.run(() => 
     { // Change the property within the zone, CD will run after 
      this.IsMobile = true; 
      this.IsDesktop = false; 
     }); 
    } 

    ShowDesktop() 
    { 
     this.zone.run(() => 
     { // Change the property within the zone, CD will run after 
      this.IsMobile = false; 
      this.IsDesktop = true; 
     }); 
    } 
} 
<home-mobile *ngIf="(IsMobile)"></home-mobile> 
<home-desktop *ngIf="(IsDesktop)"></home-desktop> 

Этот подход работает. Я могу загрузить соответствующий компонент в ответ на устройство. Это дает мне возможность настраивать компонент (контент, стиль, функциональность и т. Д.) На устройство, что позволяет наилучшим образом работать с пользователями. Это также дает мне возможность настраивать таргетинг на различные компоненты для мобильных устройств, планшетных компьютеров и настольных компьютеров (хотя в основном я ориентируюсь только на мобильные и настольные компьютеры).

Есть ли лучший способ сделать это? Недостатком является то, что я заставляю каждый компонент состоять из родительского компонента, чтобы определить через MatchMediaService, какой дочерний компонент загрузить. Будет ли это масштабируемо работать в полномасштабном приложении уровня производительности? Я очень заинтересован в ваших отзывах о лучшем подходе, или если этот подход приемлем и масштабируется для полнофункционального приложения для производства. Спасибо за отзыв.

ответ

2

Вы можете создать собственную структурную директиву, ориентированную на носители, *ngIf или *ngSwitch, чтобы сделать ее менее повторяющейся.

https://angular.io/docs/ts/latest/guide/structural-directives.html

+1

Том, это дизайн сделает настольные компоненты и мобильные компоненты живут в одной и той же сборки, которые означает большой пакет, который имеет неиспользуемый код. Вы не сможете встряхнуть его, как он использовал, но не используется. Например, '' никогда не будет работать на рабочем столе, не так ли? –

+0

Спасибо за ответ. Я не мог найти ничего конкретного в отношении структурных директив, связанных со СМИ, в указанном вами URL-адресе. Я использую структурную директиву ngIf для загрузки дочернего компонента и использование MatchMediaService для аспект носителя, обеспечивающий точку принятия решения для ngIf. Что мне не хватает? –

+1

У вас есть идея? Кажется, что команда Angular хочет предоставить что-то готовое, но не может придумать хороший подход. '@View()' должен был помочь здесь, но был сброшен, потому что это не сработало. –

-1

Не удалось избежать всего, что логика маршрутизации лениво загруженных модулей, то есть. мобильным, настольным, независимо от того, чтобы app.component перешел на маршрут соответствующего модуля на основе navigator.userAgent? От https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent

мы рекомендуем посмотреть на строку «Mobi» где-нибудь в User Agent для обнаружения на мобильное устройство

https://embed.plnkr.co/NLbyBEbNoWd9SUW7TJFS/

Смежные вопросы