我无法让svg <use>
元素在任何浏览器中在iOS上工作。它也不能在Mac上的Safari上工作。它在Android和我在PC或Mac上测试过的所有其他浏览器上都能工作。换句话说,这可能是一个webkit问题。当<path>
className根据系统/用户输入和更改动态更新时,环境为React。这个<path>
元素是使用viewBox隐藏的,并由一个大svg元素中的<use>
元素引用。这是React jsx生成的HTML:
<form
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="0" height="0" viewBox="0 0 0 0">
...
<path id="path9146scheduleamap" name="path9146scheduleamap" d="m 146.86174,202.08294 v -13.04313 h 19.67563 v 13.04313 z m 0,0" class="alert00During"></path>
...
</svg>
<div class="container-fluid">
<div class="row">
<div class="col">
<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="mapSVG" version="1.1" viewBox="0 0 199.58284 125.05578" preserveAspectRatio="xMinYMin meet" xmlns:svgjs="http://svgjs.dev/svgjs" width="100%" class="mapSVGClass" style="cursor: move; user-select: none; touch-action: none; transform-origin: 50% 50%; transition: none 0s ease 0s; transform: scale(0.67032) translate(-107.635px, -394.821px);">
...
<use id="use_path9146scheduleamap" href="#path9146scheduleamap" xlink:href="#path9146scheduleamap" d="m 146.86174,202.08294 v -13.04313 h 19.67563 v 13.04313 z m 0,0" transform="matrix(1,0,0,1,-8.574823231476401,-100.56069682128418)"></use>
...
</svg>
</div>
</div>
</div>
</form>
下面是更新svg path元素的React代码。
class Venues extends Component{
...
map2Venues(venue){
return (
<path
id={venue.mapIdentifier}
name={venue.mapIdentifier}
key={venue.mapIdentifier}
d={venue.pathD}
className={venue.alertClass}
/>
);
}
...
render() {
...
return (
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="0" height="0" viewBox="0 0 0 0" >
{this.reducedVenues.map((venue) => this.map2Venues(venue))}
</svg>
);
...
}
}
下面是svg元素和<use>
元素的React:
class Map extends Component {
...
render() {
...
return (
<Container fluid>
<Row>
<Col>
<div
id="svgMapDiv"
ref={this.svgDivRef}
dangerouslySetInnerHTML={{ __html: this.props.svgMap }}
/>
</Col>
</Row>
</Container>
);
...
}
}
带有<use>
元素的svg在组件创建时只加载一次,而带有<path>
元素的svg中的class属性会频繁更新。我理解内联svg的危险。它是受控的。如果这是webkit的bug,那么React的解决方案将受到欢迎。
UPDATE我在MacOS的Safari中确认,当<path>
元素和对应的属性在引用<use>
元素创建之前静态应用并存在时,属性会正确传播到<use>
元素。更多的证据是,当<path>
元素动态更新时,<use>
元素不会更新。
我发现这个bug description似乎没有解决。我尝试了Stuart P. Bentley于2013-03-09 14:34:36在那个bug描述中,但它仍然不起作用。也就是说,当属性被直接更改而不是通过类或样式属性(一个真实的的痛苦)时,它仍然不能在所有iOS浏览器和MacOS上的Safari上工作(但在所有其他浏览器和操作系统上工作)。例如,更改上面的Venues组件的React代码仍然不起作用:
class Venues extends Component{
...
map2Venues(venue){
let fill = "";
let stroke = "";
let stroke_width = "";
let animation_name = "";
let animation_duration = "";
let animation_iteration_count = "";
if(venue.alertClass.includes("alertSelected")){
fill = "purple";
stroke = "purple";
stroke_width = "1";
}else if(venue.alertClass.includes("alert00During")){
fill = "green";
stroke = "green";
stroke_width = "1";
}
...
return (
<path
id={venue.mapIdentifier}
name={venue.mapIdentifier}
key={venue.mapIdentifier}
d={venue.pathD}
opacity="0.8"
fill={fill}
stroke={stroke}
stroke-width={stroke_width}
/>
);
}
...
render() {
...
return (
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="0" height="0" viewBox="0 0 0 0" >
{this.reducedVenues.map((venue) => this.map2Venues(venue))}
</svg>
);
...
}
}
因此,我仍然需要一个解决这个bug的方法,因为它似乎没有被解决。(这难道不是一个重要的功能吗,特别是因为所有其他浏览器和平台都支持它?)
1条答案
按热度按时间1aaf6o9v1#
解决方法:据我所知,iOS,Safari和webkit移动的浏览器仍然不支持使用典型的React组件更新来动态更新SVG图像中的
<use>
元素。它也不支持在SVG元素被添加到React DOM之后(即在使用dangerouslySetInnerHTML
调用之后)直接修改SVG元素。但是,可以在调用dangerouslySetInnerHTML
之前直接修改SVG**,方法是使用javascript(或jQuery)修改SVG文本。一般步骤:
1.创建
<defs>
元素,1.创建新样式的
<path>
并将其添加到此<defs>
元素(<use>
元素引用的<path>
),1.抓取SVG文本
let newSvgMap = this.state.svgMap
;1.使用javascript或jQuery将
<defs>
元素添加到newSvgMap
中。1.通过使用
this.setState({ svgMap: newSvgMap })
调用更新状态,更新dangerouslySetInnerHTML
,从而使用新的<path>
样式更新组件,然后1.通过创建新的
<def>
并替换this.state.svgMap
文本中的前一个,对样式的任何更改重复此过程。示例:
注意事项:
1.我会直接设置
<path>
的属性,而不是使用类。1.我将使用已经添加的空
<defs id="myUniqueId-defs"><\/defs>
初始化SVG文件,以使react中的javascript更简单(否则您还必须添加初始<defs>
,而不是简单的替换。1.我已经测试过这适用于动画。我假设它适用于正常静态SVG元素中支持的任何功能。
这不是最有效的解决方案,但据我所知,这是唯一一个在iOS、Safari和webkit移动的浏览器中动态更新SVG元素样式的解决方案。