当使用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>
然后:
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 : '/'
})
;
请注意,我没有在小提琴中重现Chrome的问题,尽管它“适用于”Firefox。
我试图用document.createElementNS()
创建我的整个SVG无效。
有人知道发生了什么吗?
答案 0 :(得分:71)
问题是我的HTML页面中有<base>
标记。因此,用于标识过滤器的IRI不再相对于当前页面,而是<base>
标记中指示的网址。
此网址也是我的主页的网址,例如http://example.com/my-folder/
。
对于主页以外的页面,例如http://example.com/my-folder/site/other-page/
,#blurred
计算为绝对网址http://example.com/my-folder/#blurred
。但是对于一个简单的GET请求,没有JavaScript,因此没有AngularJS,这只是我的基页,没有加载模板。因此,此页面上的#blurred
过滤器不存在。
在这种情况下, Firefox 不会呈现<rect>
(是正常行为,请参阅W3C recommandation)。 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>
相关: SVG Gradient turns black when there is a BASE tag in HTML page?
答案 1 :(得分:1)
这看起来像我之前观察过的一种行为。根本原因是您最终拥有具有相同ID(模糊)的多个元素(过滤器)。不同的浏览器以不同的方式处理它......
以下是我为重现您的案例所做的工作:http://jsfiddle.net/z5cwZ/ 它有两个svg,一个是隐藏的,firefox没有显示。
避免冲突的ID有两种可能性。首先,您可以从模板中生成唯一ID(我无法帮助您使用angularjs)。以下是一个示例:http://jsfiddle.net/KbCLB/1/
使用angularjs可能更容易的第二种可能性是将过滤器放在单个svgs(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>
答案 2 :(得分:0)
刚遇到这个问题。从@ Blackhole的答案扩展而来,我的解决方案是添加一个更改每个fill属性值的指令。
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));
}
};
});
答案 3 :(得分:0)
我最近遇到过这个问题,如果在不同的路由上使用svg,你必须将$ location添加到每个路径。 实现这一点的更好方法是使用window.location.href而不是$ location服务。
答案 4 :(得分:0)
还有svg link:hrefs的问题,是的,问题是由于<base>
- 由于Strict Contextual Escaping限制,我在连接绝对网址时抛出了错误。
我的解决方案是编写一个添加了绝对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错误