如何根据某人是否使用移动设备更改我的 Angular 组件 HTML?

How do I change my Angular component HTML based on whether someone is using a mobile device?

我想配置我的 Angular 9 应用程序以根据是否有人使用移动设备查看组件来显示不同的组件。当我以前在 Python 中构建模板时,有一个 user_agents 包可以让我根据移动路径

检测和提供不同的 HTML
{% load user_agents %}
...
{% if not request|is_mobile and not request|is_tablet %}
            <td>{{ item.category }}</td>
            <td><a href="{{ item.path }}">{{ item.title }}</a></td>
            <td align="center">{{ item.created_on }}</td>
{% else %}
            <td>
                <div>
                    {{ item.category }} · {{ item.created_on_fmted }}
                </div>
                <div>
                    <a href="{{ item.mobile_path }}">{{ item.title }}</a>
                </div>
            </td>
{% endif %}

现在我正在 Angular 中构建,我有下面的 mat-table 用于我的常规设备

<mat-table #table [dataSource]="dataSource">

    <ng-container matColumnDef="category">
      <mat-header-cell *matHeaderCellDef> category </mat-header-cell>
      <mat-cell *matCellDef="let item">{{ item.category.path }}</mat-cell>
    </ng-container>

    <ng-container matColumnDef="title">
      <mat-header-cell *matHeaderCellDef> item </mat-header-cell>
      <mat-cell *matCellDef="let item"><a href='{{ item.path }}'>{{ item.title }}</a></mat-cell>
    </ng-container>

    <ng-container matColumnDef="date">
      <mat-header-cell *matHeaderCellDef> Date </mat-header-cell>
      <mat-cell *matCellDef="let item">{{ item.created_on }}</mat-cell>
    </ng-container>

  <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
  <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
</mat-table>

但我不清楚 Angular 检测我是否在移动设备上并适当更改 HTML 的方法是什么。我宁愿不检测屏幕尺寸,因为这似乎不是万无一失的。

Angular 是 SPA,这意味着所有内容都一起加载(惰性模块等也存在,但请记住这个想法)。所以你首先需要知道是移动应用程序。

有两种方法,使用 APP_Initialize 或使用不同的 .html

使用 APP_INITIALIZER 它只在您的 main.module

中定义了一个函数
export function init_app(configService: ConfigService) {
    return () => configService.getIfisMobile();
}
@NgModule({
    declarations: [AppComponent],
    imports: [
       ...
    ],
    providers: [
        { provide: APP_INITIALIZER, useFactory: init_app, deps: [ConfigService], multi: true },
    ],
    bootstrap: [AppComponent]
})

你的ConfigService有点像

@Injectable({
    providedIn: 'root',

})
export class ConfigService {
    isMobile:boolean=false;
    constructor(private httpClient: HttpClient) {}

    getIfisMobile() {
       return this.httpClient.get("your-url-get-isMobile")
            .toPromise()
            .then((response: any) => {
                this.isMobile = response;
            })
            .catch(err => {
            });
    }
 }

然后,任何在构造函数ConfigService中注入的组件都可以询问this.configService.isMobile

另一种方法是我们是否可以提供 .html。在我们的 .html 中,我们可以以任何方式添加一点 javascript,例如

<script>var isMobile=true</script>
//or is is not Mobile
<script>var isMobile=false</script>

我们可以在main.component.ts中询问并存储在服务中(*)

  constructor(@Inject(WINDOW) public window: Window, private configService: ConfigService) {
    this.configService.isMobile = (window as any).isMobile;
  }

更新 ::glups: 我忘了 window.service

/* Create a new injection token for injecting the window into a component. */
export const WINDOW = new InjectionToken('WindowToken');

/* Define abstract class for obtaining reference to the global window object. */
export abstract class WindowRef {

  get nativeWindow(): Window | Object {
    throw new Error('Not implemented.');
  }

}

/* Define class that implements the abstract class and returns the native window object. */
export class BrowserWindowRef extends WindowRef {

  constructor() {
    super();
  }

  get nativeWindow(): Window | Object {
    return window;
  }

}

/* Create an factory function that returns the native window object. */
export function windowFactory(browserWindowRef: BrowserWindowRef, platformId: Object): Window | Object {
  if (isPlatformBrowser(platformId)) {
    return browserWindowRef.nativeWindow;
  }
  return new Object();
}

/* Create a injectable provider for the WindowRef token that uses the BrowserWindowRef class. */
const browserWindowProvider: ClassProvider = {
  provide: WindowRef,
  useClass: BrowserWindowRef
};

/* Create an injectable provider that uses the windowFactory function for returning the native window object. */
export const windowProvider: FactoryProvider = {
  provide: WINDOW,
  useFactory: windowFactory,
  deps: [WindowRef, PLATFORM_ID]
};

/* Create an array of providers. */
export const WINDOW_PROVIDERS = [
  browserWindowProvider,
  windowProvider
];

(*)在服务中存储是获取“全局变量”的更方便的方式

因此您可以使用 Navigator userAgent.

中可用的数据检测用户是否在 desktop/tablet/mobile 上

您可以编写自己的 Angular 服务来执行此操作,但简单的解决方案是使用诸如 ngx-device-detector 之类的库。它提供了一项服务(在后台使用 navigator.userAgent),您可以将其注入组件以检测 device/platform 用户是什么 运行.

您可以在您的组件中使用它,例如:

constructor(private deviceService: DeviceDetectorService) {}

isMobile = this.deviceService.isMobile();

然后在您的模板中:

<div *ngIf="isMobile">I only appear on mobile</div>

更好的方法是将其包装在一个指令中,这样您就不必在许多组件中重复此代码。

import { Directive, OnInit, TemplateRef, ViewContainerRef } from '@angular/core';
@Directive({
  selector: '[isMobile]'
})
export class IsMobileDirective implements OnInit {

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

  ngOnInit() {
    if (this.deviceService.isMobile()) {
      this.viewContainer.createEmbeddedView(this.templateRef);
    } else {
      this.viewContainer.clear();
    }
  }
}

现在,您只需在组件模板内的任何元素上使用此指令即可轻松地根据设备呈现内容(请注意,此结构指令需要星号):

<div *isMobile>I only appear on mobile</div>

同样,您也可以根据需要创建 isDesktopisTabletisNotMobile 指令。