34

在将 SVG 与 AngularJS 一起使用时,我遇到了一个奇怪的行为。我正在使用该$routeProvider服务来配置我的路线。当我将这个简单的 SVG 放入模板时,一切都很好:

<div id="my-template">
    <svg xmlns="http://www.w3.org/2000/svg" version="1.1">
        <rect fill="red" height="200" width="300" />
    </svg>
    // ...
</div>

但是当我添加一个过滤器时,例如使用以下代码:

<div id="my-template">
    <svg xmlns="http://www.w3.org/2000/svg" version="1.1">
        <defs>
            <filter id="blurred">
                <feGaussianBlur stdDeviation="5"/>
            </filter>
        </defs>
        <rect style="filter:url(#blurred)" fill="red" height="200" width="300" />
    </svg>
</div>

然后:

  • 它适用于我的主页
  • 使用Firefox时,SVG在其他页面上不再可见,但它仍然会在原处留出空间。使用Chrome,SVG 是可见的,但一点也不模糊。
  • 当我手动(使用 Firebug)删除filter样式时,SVG 再次可见。

这是路由配置:

$routeProvider
    .when('/site/other-page/', {
            templateUrl : 'view/Site/OtherPage.html',
            controller : 'Site.OtherPage'
    })
    .when('/', {
            templateUrl : 'view/Site/Home.html',
            controller : 'Site.Home'
    })
    .otherwise({
        redirectTo : '/'
    })
;

Fiddle

请注意,我未能在 Fiddle 中重现 Chrome 的问题,尽管它在 Firefox 中“有效”。

我试图用document.createElementNS().

有人知道发生了什么吗?

4

5 回答 5

72

问题

问题是我的 HTML 页面中有一个<base>标签。因此,用于识别过滤器的IRI不再与当前页面相关,而是与<base>标记中指示的 URL 相关。

例如,这个 URL 也是我主页的 URL http://example.com/my-folder/

http://example.com/my-folder/site/other-page/例如,对于主页以外的页面,#blurred计算为绝对 URL http://example.com/my-folder/#blurred。但是对于一个简单的 GET 请求,没有 JavaScript,因此没有 AngularJS,这只是我的基本页面,没有加载模板。因此,此页面上不存在#blurred过滤器。

在这种情况下,Firefox不会呈现<rect>(这是正常行为,请参阅W3C 建议)。Chrome根本不应用过滤器。

对于主页,#blurred也计算为绝对 URL http://example.com/my-folder/#blurred。但这一次,这也是当前的 URL。不需要发送 GET 请求,因此#blurred过滤器存在

我应该看到对 的附加请求http://example.com/my-folder/,但在我的辩护中,它在大量其他对 JavaScript 文件的请求中丢失了。

解决方案

如果<base>标签是强制性的,解决方案是使用绝对 IRI 来识别过滤器。在 AngularJS 的帮助下,这非常简单。在控制器或链接到 SVG 的指令中,注入$location服务并使用absUrl()getter:

$scope.absUrl = $location.absUrl();

现在,在 SVG 中,只需使用这个属性:

<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
    <defs>
        <filter id="blurred">
            <feGaussianBlur stdDeviation="5"/>
        </filter>
    </defs>
    <rect style="filter:url({{absUrl}}#blurred)" fill="red" height="200" width="300" />
</svg>

相关: 当 HTML 页面中有 BASE 标记时,SVG 渐变变黑?

于 2013-11-03T13:26:00.507 回答
1

这看起来像是我之前观察到的一种行为。根本原因是您最终拥有多个具有相同 id(模糊)的元素(过滤器)。不同的浏览器处理方式不同...

这是我为重现您的案例所做的:http: //jsfiddle.net/z5cwZ/ 它有两个 svg,一个是隐藏的,firefox 没有显示。

有两种方法可以避免 id 冲突。首先,您可以从您的模板中生成唯一的 id(我无法使用 angularjs 来做这件事)。这是一个例子:http: //jsfiddle.net/KbCLB/1/

第二种可能性,使用 angularjs 可能更容易,是将过滤器放在单个 svg 之外(http://jsfiddle.net/zAbgr/1/):

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="0" height="0">
    <defs>
        <filter id="blurred">
            <feGaussianBlur stdDeviation="10" />
        </filter>
    </defs>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" style="display:none">
    <rect style="filter:url(#blurred)" fill="red" height="200" width="300" />
</svg>
<br/>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
    <rect style="filter:url(#blurred)" fill="red" height="200" width="300" />
</svg>
于 2013-11-02T15:26:35.943 回答
0

我最近自己遇到了这个问题,如果 svg 用于不同的路线,您将不得不将 $location 添加到每个路径。实现这一点的更好方法是只使用 window.location.href 而不是 $location 服务。

于 2016-05-06T18:34:21.833 回答
0

svg link:hrefs 也有问题,是的,问题是因为- 由于严格的上下文转义限制<base>,我在连接绝对 url 时抛出了错误。

我的解决方案是编写一个添加绝对 url 并信任连接的过滤器。

angular.module('myApp').filter('absUrl', ['$location', '$sce', function ($location, $sce) {
    return function (id) {
        return $sce.trustAsResourceUrl($location.absUrl() + id);
    };
}]);

然后像这样使用它:{{'#SVGID_67_' | absUrl}

结果:http://www.example.com/deep/url/to/page#SVGID_67_并且没有 $sce 错误

于 2017-02-03T15:26:44.890 回答
0

刚遇到这个问题。从@Blackhole 的答案扩展,我的解决方案是添加一个指令来更改每个填充属性的值。

angular.module('myApp').directive('fill', function(
    $location
) { 'use strict';
    var absUrl = 'url(' + $location.absUrl() + '#';

    return {
        restrict: 'A',
        link: function($scope, $element, $attrs) {
            $attrs.$set('fill', $attrs.fill.replace(/url\(#/g, absUrl));
        }
    };
});
于 2015-09-03T06:35:26.223 回答