我正在尝试使用knockoutJS动态渲染一些SVG。换句话说,ajax响应会返回有效的SVG,我希望svgweb能够动态显示它。
注意 - 这个问题是用回答你自己的问题功能编写并回答的,所以我希望能在一小时左右的时间里保存下一个人。
答案 0 :(得分:1)
如this answer中所述,您需要使用svgweb公开的appendChild方法。请注意,它接受实际的节点,而不仅仅是文本。
为了简化操作,您可以删除任何来自您的ajax响应的<xml>
或<doctype>
个节点。然后,在用jQuery包装剥离的文本之后,结果的第0个节点应该是一个有效的svg节点,可以传递给appendChild
下面的淘汰扩展包含了这个功能。
ko.bindingHandlers.renderSvg = {
init: renderSvg,
update: renderSvg
};
function renderSvg(element, valueAccessor, allBindingsAccessor, viewModel) {
var rawVal = valueAccessor();
var svgText = ko.utils.unwrapObservable(rawVal);
if (!svgText) {
element.innerHTML = '';
} else {
//clear out previous content
element.innerHTML = '';
//strip out any `<xml>` or <!doctype> tags that come over
if (svgText.indexOf('<svg') > 0){
svgText = svgText.substr(svgText.indexOf('<svg'));
}
window.svgweb.appendChild($(svgText)[0], element);
}
};
当然还有:
<div data-bind="renderSvg: mySvgField"></div>
修改强>
事实证明,使用jQuery包装SVG字符串,并尝试附加结果会导致问题。我找到的修复是使用jQuery包装父$ svg,然后使用jQuery循环遍历所有子节点。对我来说,天真的1级搜索就足够了。显然,更复杂的用例需要递归搜索。更新的代码如下。
function renderSvg(element, valueAccessor, allBindingsAccessor, viewModel) {
var rawVal = valueAccessor();
var svgText = ko.utils.unwrapObservable(rawVal);
if (!svgText) {
element.innerHTML = '';
} else {
element.innerHTML = '';
if (svgText.indexOf('<svg') > 0){
svgText = svgText.substr(svgText.indexOf('<svg'));
}
if (!$.browser.msie || $.browser.version > 8){
//normal browsers
window.svgweb.appendChild($(svgText)[0], element);
} else {
//IE 8
var $svg = $(svgText);
var svg = document.createElementNS(svgns, 'svg');
svg.setAttribute('width', $svg.attr('width'));
svg.setAttribute('height', $svg.attr('height'));
$.each($svg.children(), function(i, el){
var path = document.createElementNS(svgns, el.tagName);
for (var i = 0, allAttributes = el.attributes, len = allAttributes.length; i < len; i++){
path.setAttribute(allAttributes.item(i).nodeName, allAttributes.item(i).nodeValue);
}
svg.appendChild(path);
});
window.svgweb.appendChild(svg, element);
}
}
}