Angular2 SVG xlink:href

时间:2016-01-29 10:51:59

标签: angular angular2-template

我有用于渲染SVG图标的组件:

import {Component, Directive} from 'angular2/core';
import {COMMON_DIRECTIVES} from 'angular2/common';

@Component({
  selector: '[icon]',
  directives: [COMMON_DIRECTIVES],
  template: `<svg role="img" class="o-icon o-icon--large">
                <use [xlink:href]="iconHref"></use>
              </svg>{{ innerText }}`
})
export class Icon {
  iconHref: string = 'icons/icons.svg#menu-dashboard';
  innerText: string = 'Dashboard';
}

这会触发错误:

EXCEPTION: Template parse errors:
  Can't bind to 'xlink:href' since it isn't a known native property ("<svg role="img" class="o-icon o-icon--large">
<use [ERROR ->][xlink:href]=iconHref></use>
  </svg>{{ innerText }}"): SvgIcon@1:21

如何设置动态xlink:href

3 个答案:

答案 0 :(得分:62)

SVG元素没有属性,因此大多数时候都需要属性绑定(另请参阅Properties and Attributes in HTML)。

对于属性绑定,您需要

<use [attr.xlink:href]="iconHref">

<use attr.xlink:href="{{iconHref}}">

<强>更新

清理可能会导致问题。

另见

更新 DomSanitizationService将在RC.6中重命名为DomSanitizer

更新这应该是固定的

但是有一个未解决的问题是支持命名空间属性https://github.com/angular/angular/pull/6363/files

随着解决方案添加额外的

xlink:href=""

Angular可以更新属性,但是存在添加问题。

如果xlink:href实际上是一个属性,那么在添加PR之后你的语法也应该有效。

答案 1 :(得分:3)

我仍然遇到Gunter描述的attr.xlink:href问题所以我创建了一个类似于SVG 4 Everybody的指令,但是特定于angular2。

用法

<div [useLoader]="'icons/icons.svg#menu-dashboard'"></div>

说明

该指令

  1. 通过http
  2. 加载图标/ icons.svg
  3. 解析响应并提取#menu-dashboard
  4. 的路径信息
  5. 将解析后的svg图标添加到html
  6. 代码

    import { Directive, Input, ElementRef, OnChanges } from '@angular/core';
    import { Http } from '@angular/http';
    
    // Extract necessary symbol information
    // Return text of specified svg
    const extractSymbol = (svg, name) => {
        return svg.split('<symbol')
        .filter((def: string) => def.includes(name))
        .map((def) => def.split('</symbol>')[0])
        .map((def) => '<svg ' + def + '</svg>')
    }
    
    @Directive({
        selector: '[useLoader]'
    })
    export class UseLoaderDirective implements OnChanges {
    
        @Input() useLoader: string;
    
        constructor (
            private element: ElementRef,
            private http: Http
        ) {}
    
        ngOnChanges (values) {
            if (
                values.useLoader.currentValue &&
                values.useLoader.currentValue.includes('#')
            ) {
                // The resource url of the svg
                const src  = values.useLoader.currentValue.split('#')[0];
                // The id of the symbol definition
                const name = values.useLoader.currentValue.split('#')[1];
    
                // Load the src
                // Extract interested svg
                // Add svg to the element
                this.http.get(src)
                .map(res => res.text())
                .map(svg => extractSymbol(svg, name))
                .toPromise()
                .then(svg => this.element.nativeElement.innerHTML = svg)
                .catch(err => console.log(err))
            }
        }
    }
    

答案 2 :(得分:0)

我认为可以使用角管功能来解决。

<use attr.xlink:href={{weatherData.currently.icon|iconpipe}}></use>

说明 该管道将​​

  1. 将已解析的响应值传递给管道
  2. 返回完整的svg路径
  3. attr.xlink:href=将获得预期的路径,并在svg中呈现 html页面

这是管道打字稿代码

import { PipeTransform, Pipe } from '@angular/core';

@Pipe({
    name: 'iconpipe'
})
export class IconPipe implements PipeTransform {
    constructor() { }

    transform(value: any) {
        let properIconName = undefined;

        switch (value) {
            case 'clear-day':
                properIconName = '/assets/images/weather-SVG-sprite.svg#sun';
                break;
            case 'clear-night':
                properIconName = '/assets/images/weather-SVG-sprite.svg#night-1';
                break;
            case 'partly-cloudy-day':
                properIconName = '/assets/images/weather-SVG-sprite.svg#cloudy';
                break;

            case 'partly-cloudy-night':
                properIconName = '/assets/images/weather-SVG-sprite.svg#night';
                break;

            case 'cloudy':
                properIconName = '/assets/images/weather-SVG-sprite.svg#cloud';
                break;

            case 'rain':
                properIconName = '/assets/images/weather-SVG-sprite.svg#rain';
                break;

            case 'sleet':
                properIconName = '/assets/images/weather-SVG-sprite.svg#snowflake';
                break;
            case 'snow':
                properIconName = '/assets/images/weather-SVG-sprite.svg#snowing';
                break;

            case 'wind':
                properIconName = '/assets/images/weather-SVG-sprite.svg#storm';
                break;
            case 'fog':
                properIconName = '/assets/images/weather-SVG-sprite.svg#sun';
                break;
            case 'humid':
                properIconName = '/assets/images/weather-SVG-sprite.svg#sun';
                break;
            default:
                properIconName = '/assets/images/weather-SVG-sprite.svg#summer';
        }
        return properIconName;
    }
}