Use knockoutjs virtual element to create html part

2019-06-20 14:59发布

问题:

I am trying to use "virtual element" with html binding to create html part on the fly but failed with message: "The binding 'html' cannot be used with virtual elements". Here is the jsfiddle: http://jsfiddle.net/d3Dpp/.

Anyone knows if there is any workaround?

回答1:

Well, after some playing with knockout I see that it is possible.

Working example is here

http://jsfiddle.net/d3Dpp/42/

unfortunatelly this requires duplication of some internal knockout functionality

UPDATE

KnockoutJS 2.2.1 added virtual elements binding to export, so it is available even in minified version:

ko.exportSymbol('virtualElements.allowedBindings', ko.virtualElements.allowedBindings);

It means that better solution for html binding is possible - see Martijn's answer.



回答2:

Based on Artem's code and KnockoutJS 2.2.1, here's an improved version:

http://jsfiddle.net/YZzDe/2/

Improvements:

  1. Less code, less duplication (hooks in to exposed interfaces)
  2. Overrides 'html' binding, so basically the old 'html' can now be used in virtuals
  3. No more global functions.

Here's the code

{
    var overridden = ko.bindingHandlers['html'].update;

    ko.bindingHandlers['html'].update = function (element, valueAccessor) {
        if (element.nodeType === 8) {
            var html = ko.utils.unwrapObservable(valueAccessor());

            ko.virtualElements.emptyNode(element);
            if ((html !== null) && (html !== undefined)) {
                if (typeof html !== 'string') {
                    html = html.toString();
                }

                var parsedNodes = ko.utils.parseHtmlFragment(html);
                if (parsedNodes) {
                   var endCommentNode = element.nextSibling;
                   for (var i = 0, j = parsedNodes.length; i < j; i++)
                      endCommentNode.parentNode.insertBefore(parsedNodes[i], endCommentNode);
                }
            }
        } else { // plain node
            overridden(element, valueAccessor);
        }
    };
}
ko.virtualElements.allowedBindings['html'] = true;


回答3:

You could also use this as your view:

<div data-bind="html: html"></div>​​​​​​​​​​​​​​​​​​​​​

This will replace the innerHtml of the div "container" with your provided html property.