Angular:从资产文件夹中读取所有文件

问题描述 投票:0回答:1

tltr:我可以从 Angular 访问资产目录吗?

我在一个文件夹

src/assets/icons
中有一堆 SVG,我与
mat-icon
一起使用。唯一的缺点是,当我添加新图标时,我必须添加文件,并且必须将文件名添加到一个数组中,我用该数组循环将其添加到
matIconRegistry
。有没有办法简单地读取目录中的所有文件?

这是我当前的解决方案:

@NgModule()
export class CustomIconModule {
  constructor(
    private matIconRegistry: MatIconRegistry,
    private domSanitizer: DomSanitizer
  ) {
    const icons = [
      'icon1', 'icon2',
    ];

    for (const icon of icons) {
      this.matIconRegistry.addSvgIconInNamespace(
        'my-namespace',
        icon,
        domSanitizer.bypassSecurityTrustResourceUrl(`./assets/icons/${icon}.svg`)
      );
    }
  }
}

更新:我编写了一个 bash 脚本,它循环遍历文件,生成一个包含所有文件名数组的 .ts 文件,并执行

git add
。我在预提交 git hook 中运行它。不太理想,但目前还可以。不过,我很想找到一个纯 JS 解决方案。

angular angular-material2
1个回答
0
投票

您可以在应用程序的构建阶段执行节点脚本。

// scripts/icons-lookup.js
const fs = require('fs');
const glob = require('glob');

const ICONS_DIRECTORY_PATH_PATTERN = 'src/assets/icons/**/*.svg';
const ICONS_FILE_PATH_PATTERN = /^src[\\/]assets[\\/]icons[\\/](?<iconFilePath>.+)\.svg$/;
const OS_SEPARATOR = require('path').sep;

const result = {};

glob.sync(ICONS_DIRECTORY_PATH_PATTERN).forEach((path) => {
  const match = ICONS_FILE_PATH_PATTERN.exec(path);
  const fragments = match[1].split(OS_SEPARATOR);
  const key = fragments.join('-').replace(' ', '-');
  const value = `${fragments.join('/')}.svg`;
  result[key] = value;
});

fs.writeFileSync('./src/assets/icons-lookup.json', JSON.stringify(result));

然后,定义一个

icons:lookup
命令,该命令在任何
ng build
/
ng serve
:

之前调用
// package.json
{
  "name": "my-application",
  "scripts": {
    "icons:lookup": "node ./scripts/icons-lookup.js", // this calls the above node script
    "before:run": "npm run icons:lookup", // intermediate command
    ...
    "build": "npm run before:run && ng build --configuration local",
    "build:dev": "npm run before:run && ng build --configuration dev",
    ...
    "serve": "npm run before:run && ng serve --configuration local",
    "serve:dev": "npm run before:run && ng serve --configuration dev",
    ...
  },

注意:我建议使用中间

before:run
命令,您可以在其中添加大量其他脚本
(例如:计算构建详细信息或创建 i18n 缓存清除信息)。

然后,当您运行应用程序时,它会生成一个 icons-lookup.json 文件(将其添加到您的 .gitignore):

{"icon1":"icon1.svg","icon2":"icon2.svg",...}

最后,您可以在模块(或服务)中利用此文件。
您可以通过

require()
同步获取,也可以通过
this.http.get
调用异步获取。

// src/app/modules/some-module/services/icon-registry/icon-registry.service.ts
import { inject, Injectable } from '@angular/core';
import { MatIconRegistry } from '@angular/material/icon';
import { DomSanitizer } from '@angular/platform-browser';

const fileMap: Record<string, string> = require('../../../../../assets/icons-lookup.json');

@Injectable({ providedIn: 'root' })
export class IconRegistryService {
  private readonly matIconRegistry = inject(MatIconRegistry);
  private readonly sanitizer = inject(DomSanitizer);

  private initialized = false;

  initialize(): void {
    if (!this.initialized) {
      Object.entries(fileMap).forEach(([iconName, fileName]) => {
        const filePath = `assets/icons/${fileName}`;
        const url = this.sanitizer.bypassSecurityTrustResourceUrl(filePath);
        this.matIconRegistry.addSvgIcon(iconName, url);
      });

      this.initialized = true;
    }
  }
}
// main.ts
const appConfig: ApplicationConfig = {
  providers: [
    ...,
    {
      provide: APP_INITIALIZER,
      useFactory: (service: IconRegistryService) => () => {
        service.initialize();
      },
      deps: [IconRegistryService],
      multi: true,
    },
  ],
};

bootstrapApplication(AppRootComponent, appConfig).catch((err) => {
  console.error(err);
});
© www.soinside.com 2019 - 2024. All rights reserved.