我正在尝试使用 knockoutJS 动态渲染一些 SVG。换句话说,一个 ajax 响应返回了有效的 SVG,我希望 svgweb 动态显示它。
注意- 这个问题是用回答你自己的问题功能编写和回答的,所以我希望可以为下一个人节省一个小时左右的搜索时间。
我正在尝试使用 knockoutJS 动态渲染一些 SVG。换句话说,一个 ajax 响应返回了有效的 SVG,我希望 svgweb 动态显示它。
注意- 这个问题是用回答你自己的问题功能编写和回答的,所以我希望可以为下一个人节省一个小时左右的搜索时间。
如本答案中所述,您需要使用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);
}
}
}