我正在开发一个SVG UI元素库,并计划使用knockout.js。这是一个非常基本的页面,可以在没有knockout.js的情况下完成我需要的工作,它在Chrome,FF,Opera中运行良好。它绘制了一条管道:
<html>
<body>
<div width="100px" height="100px">
<svg width='100px' height='100px'>
<linearGradient id="gradId" y1='-20%' x1='0%' y2='100%' x2='0%' gradientUnits='objectBoundingBox'>
<stop offset='-20%' style="stop-color: #303030"/>
<stop offset='40%' style="stop-color: #D0D0D0"/>
<stop offset='100%' style="stop-color: #303030"/>
</linearGradient>
<rect id="myRect" x='0%' y='30%' width='100%' height='40%' />
</svg>
</div>
<script type="text/javascript">
document.getElementById("myRect").style.fill = "url(#gradId)";
console.log(document.getElementById("myRect").style.fill);
</script>
</body>
</html>
现在来到knockout.js模板。对于模板化控件的每个实例,我将需要唯一的id,因此正确引用相应的渐变,并且不同的管道元素不共享渐变。在this post的帮助下,我制作了以下html:
<html>
<head>
<script type="text/javascript" src="js/knockout-2.1.0.debug.js "></script>
<script type="text/javascript">
// knockout code inspired by https://stackoverflow.com/questions/9233176/unique-ids-in-knockout-js-templates
ko.bindingHandlers.uniqueId = {
init: function (element, valueAccessor) {
// Generate new element id
element.id = ko.bindingHandlers.uniqueId.prefix + valueAccessor() + ko.bindingHandlers.uniqueId.prefix + (++ko.bindingHandlers.uniqueId.counter);
console.log("Element id:" + element.id);
},
prefix: "autoId_",
counter: 0
};
ko.bindingHandlers.uniqueStyleFill = {
init: function (element, valueAccessor) {
// Use recently generated element id in the style.fill value
var value = ko.bindingHandlers.uniqueId.prefix + valueAccessor() + ko.bindingHandlers.uniqueId.prefix + ko.bindingHandlers.uniqueId.counter.toString();
element.style.fill = "url(#" + value + ")";
console.log("Binding:" + element.style.fill);
}
};
</script>
</head>
<body>
<!-- Define ko template plumbing-horizontal-pipe that uses bodyColor and bodyColorLight attributes of the bound object -->
<script type="text/html" id="plumbing-horizontal-pipe">
<svg width='100px' height='100px'>
<linearGradient data-bind="uniqueId: 'horPipeGrad_'" y1='-20%' x1='0%' y2='100%' x2='0%' gradientUnits='objectBoundingBox'>
<stop offset='-20%' data-bind="style: {'stop-color': bodyColor()}"/>
<stop offset='40%' data-bind="style: {'stop-color': bodyColorLight()}"/>
<stop offset='100%' data-bind="style: {'stop-color': bodyColor()}"/>
</linearGradient>
<rect x='0%' y='30%' width='100%' height='40%' data-bind="uniqueStyleFill: 'horPipeGrad_'"/>
</svg>
</script>
<div width="100px" height="100px">
<!-- Load ko template defined above, bind 'pipe' -->
<svg width="100" height="110" data-bind="template: { name: 'plumbing-horizontal-pipe', data: pipe }" />
</div>
<!-- ko view model with one item 'pipe' -->
<script type="text/javascript">
function MyViewModel() {
this.pipe = { bodyColor: ko.observable("#FF0000"), bodyColorLight: ko.observable("#FFA0A0") };
}
var g_vm = new MyViewModel();
// This should make the browser display a red pipe. Works in Chrome, doesn't work in FF and Opera.
ko.applyBindings(g_vm);
</script>
</body>
</html>
在Chrome中工作正常 - 显示红色管道。 FF和Opera保持显示黑色矩形,这意味着SVG对象不会拾取渐变。我检查了FF日志输出,它看起来完全正常:
[21:30:08.606] Element id:autoId_horPipeGrad_autoId_1
[21:30:08.610] Binding:url("#autoId_horPipeGrad_autoId_1") none
可以看到,生成渐变的id并在rect样式的fill属性中使用。但是在显示矩形时浏览器不使用此渐变。
这里有什么问题?任何解决方法? 谢谢!
答案 0 :(得分:0)
我发现如果我使用svg节点属性的本机KO绑定,最好使用'attr'绑定。 事实上它似乎解决了你的问题:http://jsfiddle.net/antishok/UHnA8/1/
(我知道'css'绑定不起作用,因为svg元素的'class'属性不是一个简单的字符串。不确定为什么'style'也不起作用,但至少attr似乎永远工作)