将SVGWeb与KnockoutJS一起使用 - 动态添加SVG

时间:2013-10-12 20:05:26

标签: javascript knockout.js svgweb

我正在尝试使用knockoutJS动态渲染一些SVG。换句话说,ajax响应会返回有效的SVG,我希望svgweb能够动态显示它。


注意 - 这个问题是用回答你自己的问题功能编写并回答的,所以我希望能在一小时左右的时间里保存下一个人。

1 个答案:

答案 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);
        }
    }
}