【问题标题】:Loading icon from Material Icon Registry errors out with "<svg> tag not found"从 Material Icon Registry 加载图标时出现“<svg> tag not found”错误
【发布时间】:2019-04-01 17:47:37
【问题描述】:

我正在尝试使用 Angular Material 7.2 和 Angular 7.2.11 实现具有自定义 SVG 图标的按钮。使用标准 Material 图标字体我没有遇到任何问题。然而,自定义图标只会导致控制台上出现“检索图标时出错:&lt;svg&gt; 未找到标签”。

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

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

_fetchUrl() 正在使用 HttpClient::get() 的 'text' responseType 选项,据我所知,这应该没问题,尽管响应指定了content-type: image/svg+xml。可以肯定的是,我重命名了 SVG 并给它一个 'txt' 扩展名。随后的响应具有 text/plain 内容类型,但 HttpResponse 的主体仍然是空的。

从等式中删除材料图标注册表并尝试简单的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>

【问题讨论】:

    标签: angular svg angular-material angular-httpclient


    【解决方案1】:

    最终将问题追溯到项目中的 HTTP 拦截器。它正在清除响应的主体。

    【讨论】:

    • 您好,我现在面临同样的问题。您是否也最终弄清楚如何防止它擦拭身体?因为我需要拦截器来为 Material-UI MatIconRegistry 中的自定义 svg 修复 SSR。
    • 在我的情况下,它是类似的,一个 http 拦截器正在替换 url 来调用后端端点。使用 path === assests ? _not replace_ : _replace_ 之类的 if 条件解决
    【解决方案2】:

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

    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`));
        });
      }
    
    }
    
    

    第 2 步:在您的 app.module.ts 中的 provider 部分下注入服务

    
    @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 { }
    

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

    import { Component } from '@angular/core';
    import { IconService } from './core/services/icon/icon.service';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html'
    
    })
    export class AppComponent {
    
      constructor(private iconService: IconService) {
        this.iconService.registerIcons();
      }
    
    }
    
    

    【讨论】:

      【解决方案3】:
      this.domSanitizer.bypassSecurityTrustResourceUrl('./assets/svg/test.svg'));
      

      你看出区别了吗?

      【讨论】:

      • 是的,我应该提到我尝试了不同的路径,但是,正如我提到的,它发现 SVG 很好,并使用 Firefox 的网络分析验证的正确 SVG 响应请求。在收到 SVG 并尝试对其进行解析后,就会出现问题。然而,为了我的理智,我确实继续尝试了修改后的路径,但没有帮助。
      猜你喜欢
      • 1970-01-01
      • 2021-02-01
      • 2017-09-03
      • 1970-01-01
      • 2017-11-25
      • 2016-10-05
      • 2013-10-14
      • 2017-03-16
      • 2021-11-02
      相关资源
      最近更新 更多