Angular和SVGfilter
在AngularJS中使用SVG时,我遇到了一个奇怪的行为。 我正在使用$routeProvider
服务来configuration我的路线。 当我把这个简单的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>
但是当我添加一个filter,例如这个代码:
<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再次可见。
这里是路由configuration:
$routeProvider .when('/site/other-page/', { templateUrl : 'view/Site/OtherPage.html', controller : 'Site.OtherPage' }) .when('/', { templateUrl : 'view/Site/Home.html', controller : 'Site.Home' }) .otherwise({ redirectTo : '/' }) ;
小提琴
请注意,我没有重现与铬在一个小提琴的问题,虽然它与Firefox“工作”。
我试图用document.createElementNS()
创build我的整个SVG无济于事。
有人知道发生了什么吗?
问题
问题是我的HTML页面中有一个<base>
标签。 因此,用于识别filter的IRI不再与当前页面相关,而是与<base>
标记中指示的URL相关。
这个URL也是我主页的URL,例如http://example.com/my-folder/
。
对于主页以外的页面,例如http://example.com/my-folder/site/other-page/
计算为绝对URL http://example.com/my-folder/#blurred
。 但对于一个简单的GET请求,没有JavaScript,因此没有AngularJS,这只是我的基本页面,没有模板加载。 因此, #blurred
不存在 #blurred
filter。
在这种情况下, Firefox不会呈现<rect>
(这是正常行为 ,请参阅W3C推荐 )。 Chrome只是不适用filter。
对于主页, #blurred
也计算为绝对URL http://example.com/my-folder/#blurred
。 但是这一次,这也是当前的URL。 不需要发送GET请求,因此存在 #blurred
filter。
我应该看到http://example.com/my-folder/
的额外请求,但是在我的辩护中,它在JavaScript文件的其他许多请求中丢失了。
解决scheme
如果<base>
标记是强制性的,解决方法是使用绝对IRI来标识filter。 在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渐变变黑了吗?
这看起来像我之前观察到的行为。 根本原因是你最终有多个元素(filter)具有相同的ID(模糊)。 不同的浏览器处理它不同…
下面是我重做你的情况: http : //jsfiddle.net/z5cwZ/它有两个SVG,一个是隐藏的,Firefox显示没有。
有两种可能性来避免冲突ID。 首先,你可以从你的模板生成独特的ID(我忍不住用尖锐的方式来做)。 这里是一个例子: http : //jsfiddle.net/KbCLB/1/
第二种可能性,使用angularjs可能会更容易,就是把filter放在个别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>
刚碰到这个问题。 从@Blackhole的答案扩展,我的解决scheme是添加一个指令,改变每个填充属性的值。
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)); } }; });
我最近自己碰到这个问题,如果svg在不同的路由上使用,你将不得不把$ location添加到每个path。 实现这一点的更好方法是使用window.location.href而不是$ location服务。
也有问题与svg链接:hrefs,是的,问题是因为<base>
– 由于严格的上下文转义限制,当连接绝对url时,我有错误。
我的解决scheme是编写一个filter,添加绝对url,也信任连接。
angular.module('myApp').filter('absUrl', ['$location', '$sce', function ($location, $sce) { return function (id) { return $sce.trustAsResourceUrl($location.absUrl() + id); }; }]);
然后像这样使用它: {{'#SVGID_67_' | absUrl}
{{'#SVGID_67_' | absUrl}
结果: http://www.example.com/deep/url/to/page#SVGID_67_
: http://www.example.com/deep/url/to/page#SVGID_67_
,没有$ sce错误