从“材料图标注册表”错误中加载图标,出现“找不到<svg>标记”

时间:2019-04-01 17:47:38

标签: angular svg angular-material angular-httpclient

我正在尝试使用Angular Material 7.2和Angular 7.2.11实现具有自定义SVG图标的按钮。使用标准的Material图标字体我没有遇到任何问题。但是,自定义图标只会导致控制台上出现“错误检索图标:<svg>标记”。

我一直在浏览@ angular / material / esm2015 / icon.js中的代码,发现_fetchUrl()似乎正在接收SVG,但是尽管ACTUAL响应包含以下内容,但HttpResponse对象的主体为空: Firefox验证的SVG。 HttpResponse对象中的标头包含正确的内容长度。

将HttpResponse对象报告的URL粘贴到浏览器中会呈现正确的SVG。

_fetchUrl()使用HttpClient :: get()的'text'responseType选项,据我所知,尽管响应指定了content-type: image/svg+xml,这还是可以的。可以肯定的是,我重命名了SVG,并为其赋予了“ txt”扩展名。后续响应的内容类型为text/plain,但是HttpResponse的正文仍然为空。

从等式中删除Material图标注册表,而仅尝试简单的get()会产生相同的问题。请求成功完成,发送了SVG,但是HttpResponse的正文为空。

应用程序模块:

import { HttpClientModule, ... } from '@angular/common/http';
import {
 ...
 MatIconModule,
 ...
} from '@angular/material';

@NgModule({
 ...
 imports: [
  ...
  HttpClientModule,
  MatIconModule
  ...
 ],
 ...
})

应用程序组件:

@Component({
 ...
})
export class AppComponent {
  constructor(private router: Router, private matIconRegistry: MatIconRegistry, private domSanitizer: DomSanitizer, private http: HttpClient, ...)
  {
    this.matIconRegistry.addSvgIcon('test_icon',
      this.domSanitizer.bypassSecurityTrustResourceUrl('/assets/svg/test.svg'));

    http.get('/assets/svg/test.svg', { responseType: 'text' })    .subscribe(svg => console.log(`Response: ${svg}`));
  }
}

组件HTML:

<button mat-icon-button>
  <mat-icon svgIcon="test_icon"></mat-icon>
</button>

测试SVG文件:

<?xml version="1.0" encoding="UTF-8" ?>
<svg width="64" height="64" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <rect x="0" y="0" width="64" height="64" style="fill:rgb(0,0,0,0)" />
</svg>
<svg>Test</svg>

控制台输出:

Request to access cookie or storage on “https://fonts.googleapis.com/icon?family=Material+Icons” was blocked because we are blocking all third-party storage access requests and content blocking is enabled. calendar

Angular is running in the development mode. Call enableProdMode() to enable the production mode. core.js:21273

Error retrieving icon: <svg> tag not found icon.js:867:81

请求/响应:

GET /assets/svg/test.svg HTTP/1.1

HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: *
Accept-Ranges: bytes
Content-Type: image/svg+xml; charset=UTF-8
Content-Length: 219
ETag: W/"d9-8SqOE9sCdf/cpMgr8wAdHVFXV+g"
Date: Tue, 02 Apr 2019 00:36:12 GMT
Connection: keep-alive
<?xml version="1.0" encoding="utf-8" ?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
  <rect x="0" y="0" width="32" height="32" style="fill:rgb(0,0,0,0)" />
</svg>

3 个答案:

答案 0 :(得分:1)

<块引用>

您可以按照此代码段在材料注册表中添加自定义材料图标。 图标 我正在维护一个枚举图标列表并用于加载图标方法。 步骤 1:首先创建一个 IconService。

  <style name="ThemeOverlay.App.Toolbar" parent="ThemeOverlay.MaterialComponents.Toolbar.Primary">
    <!-- color used by navigation icon and overflow icon -->
    <item name="colorOnPrimary">@color/myColor</item>
  </style>

第 2 步:在提供者部分下的 app.module.ts 中注入服务

import { Injectable } from '@angular/core';
import { MatIconRegistry } from '@angular/material/icon';
import { DomSanitizer } from '@angular/platform-browser';
import { environment } from 'src/environments/environment';
import { Icons } from '../../enums/icons.enum';

@Injectable({
  providedIn: 'root'
})
export class IconService {

  baseURL: string = environment.baseURL;
  constructor(
    private matIconRegistry: MatIconRegistry,
    private domSanitizer: DomSanitizer
  ) { }

  public registerIcons(): void {
    this.loadIcons(Object.values(Icons), this.baseURL + 'assets/svg/icons');
  }

  private loadIcons(iconKeys: string[], iconUrl: string): void {
    iconKeys.forEach(key => {
      debugger;
      this.matIconRegistry.addSvgIcon(key, this.domSanitizer.bypassSecurityTrustResourceUrl(`${iconUrl}/${key}.svg`));
    });
  }

}

<块引用>

第 3 步:在构造函数 app.component.ts 文件中注入图标服务并调用 registerIcons 方法


@NgModule({
  declarations: [
    AppComponent,
    NavMenuComponent
  ],
  imports: [
    AppRoutes,
    NgbModule,
    BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
    HttpClientModule,
    FormsModule,
    BrowserAnimationsModule,
    MatMenuModule,
    MatSidenavModule,
    MatIconModule,
    MatTooltipModule,
    ToastrModule.forRoot(),
  ],
  providers: [ ToastrService , CookieService, ErrorService, HttpService, StorageService, IconService
   ],
  bootstrap: [AppComponent]
})
export class AppModule { }

答案 1 :(得分:0)

this.domSanitizer.bypassSecurityTrustResourceUrl('./assets/svg/test.svg'));

您看到区别了吗?

答案 2 :(得分:0)

最后,将问题追溯到项目中的HTTP拦截器。它消除了响应的主体。