我对此完全没有经验,所以要谦虚;-)。
我正在尝试制作类似Inkscape中的动画图标集的东西。 为了向矩形“符号”添加行为,我向其中添加了一些Javascript。到目前为止,一切都很好。如果我在'use'标签的帮助下克隆'symbol'并将其悬停在矩形上,它会像应该的那样改变颜色。
这是问题所在:如果我用'use'标签创建了第二个克隆,那么当我将鼠标悬停在另一个上时,两个副本的颜色都会改变。
那不是我想要的。我希望'use1'独立于'use2'来改变颜色。同时,我希望脚本成为'symbol'标签的一部分,而不是'use'标签的一部分。
示例代码(未成功):
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<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"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="210mm"
height="297mm"
viewBox="0 0 210 297"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r15371"
sodipodi:docname="rectangle.svg">
<script
type="text/javascript"
href="svg.js"
id="script5609" />
<defs
id="defs2">
<symbol
id="symbol7630"
onmouseover="console.log(evt.target)"
onmouseout="evt.target.style.fill='blue'">
<rect
style="fill:#ff0000;stroke:#00fb00;stroke-width:3.16499996;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="BigRect"
width="57.452377"
height="36.285713"
x="61.988094"
y="47.535706" />
<rect
style="fill:#ff0000;stroke:#00fb00;stroke-width:3.16499996;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="SmallRect"
width="21.166666"
height="35.529762"
x="143.63095"
y="45.267857" />
<script
type="text/javascript"
id="script5613"><![CDATA[
var element = SVG.get('SmallRect')
element.style('fill', 'yellow')
element.click(function() {
this.style('fill', 'green')
})
element.mouseover(function() {
this.style('fill', 'red')
})
element.mouseout(function() {
this.style('fill', 'blue')
})
//element.attr('fill', '#c06')
//element.fill('#c06')
//element.stroke(
]]></script>
</symbol>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.75722503"
inkscape:cx="104.33497"
inkscape:cy="561.25984"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<!-- Specify the place where the animation library svg.js can be found -->
<use
xlink:href="#symbol7630"
id="use16221"
transform="translate(-15.72353,1.3976471)"
x="0"
y="0"
width="100%"
height="100%" />
<use
id="use3984"
xlink:href="#symbol7630"
x="0"
y="0"
width="100%"
height="100%"
transform="translate(-20.449326,79.41301)" />
<use
id="use4008"
xlink:href="#symbol7630"
x="0"
y="0"
width="100%"
height="100%"
transform="translate(-37.570503,138.11419)" />
</g>
</svg>
答案 0 :(得分:1)
您的示例代码并不理想,因为您尝试做的某些事情或某些事情只能用不带Javascript的CSS来实现,而其他一些事情可以用SMIL动画更优雅地完成(再次避免使用Javascript,但目前付出了一些代价浏览器兼容性问题)。但是由于您的问题始于尝试编写脚本,所以我将从那里开始。
不管做什么,保持快速的一件事是,将与该符号的所有实例同步执行与<symbol>
关联的脚本。同样困难的规则是,为符号成员元素设置的样式将应用于该元素的所有实例。
但是第二条规则在边缘有一些缝隙:您不需要在style属性中设置style属性,但是CSS级联提供了以下机会:a)一次性为所有适合选择器的元素设置属性; b)从其父级继承属性。这就是窍门:如果您通过一个<symbol>
元素引用一个<use>
,该实例将从单个<use>
元素继承样式属性。
您必须做的第一件事是从fill
属性中删除style
属性。这样,其值可以从父级<use>
继承。然后,选择样式表中的所有<use>
元素,并在其中定义一个fill
。我正在将这种图案用于大矩形。
请注意:如果定义<style>
元素,Inkscape会将其内容分发到目标元素并将其添加到本地style
属性中。这违背了CSS级联的目的,并且会破坏我在这里描述的内容。 Inkscape是一个不错的设计器工具,但是在为网络编程时不要依赖它!
这个小矩形具有仅CSS的解决方案,用于在悬停时更改颜色:如果将鼠标悬停在<use>
元素上,则其自身的属性会更改,并且属性值会向下继承。您可以设置一个use:hover {fill: red}
规则,但这会使所有没有更具体规则的元素变为红色。相反,我设置了property variable --small-rect-fill: red
,并用fill:var(--small-rect-fill)
的小矩形进行引用。您可以根据需要定义任意多个变量。
对于脚本编写,您必须遵循相同的基本路径:更改<use>
元素上的属性以使其能够被继承。无法直接定位内部的符号实例(此“影子树”的成员是只读的)。这里的问题是,您需要一个脚本,该脚本由每个<use>
元素上的事件触发,并且可以区分它们。有两种可能的解决方案。优雅的事件委托,我只去hint at,然后讲第二个简单的事:首先定义您的侦听器函数,然后将其附加到每个目标元素。
作为一个抽象问题(为了避免出现兼容性问题,事实证明),我不是直接在<use>
元素上设置样式,而是添加/删除一个类,该类会更改属性变量。
我希望能涵盖您所想到的用例。
var elements = document.querySelectorAll('use');
var onclick = function (event) {
event.target.classList.add('clicked');
};
var onmouseout = function (event) {
event.target.classList.remove('clicked');
};
elements.forEach(function (el) {
el.addEventListener('click', onclick);
el.addEventListener('mouseout', onmouseout);
});
rect {
stroke: #00fb00;
stroke-width: 3.165;
}
use {
fill: red;
--small-rect-fill: yellow;
}
use:hover {
--small-rect-fill: red;
}
use.clicked {
--small-rect-fill: green;
}
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 210 297">
<defs>
<symbol id="symbol7630">
<rect
id="BigRect"
width="57.452377"
height="36.285713"
x="61.988094"
y="47.535706" />
<rect
style="fill:var(--small-rect-fill)"
id="SmallRect"
width="21.166666"
height="35.529762"
x="143.63095"
y="45.267857" />
</symbol>
</defs>
<g>
<use
xlink:href="#symbol7630"
transform="translate(-15.72353,1.3976471)" />
<use
xlink:href="#symbol7630"
transform="translate(-20.449326,79.41301)" />
<use
xlink:href="#symbol7630"
transform="translate(-37.570503,138.11419)" />
</g>
</svg>