javascript - 将 Knockout.js 与自定义模板引擎结合使用

标签 javascript knockout.js vis.js

我正在尝试获取 timeline component of vis.js与 Knockout.js 一起工作。

时间线有 templates option它允许您为时间线上的每个事件编写自定义 HTML。就我而言,它看起来像这样:

var options = {
    ... // other options
    template: function(item) {
        var html = '<b>' + item.subject + '</b>'+
                '<p>' + item.owner.username + ' (' + item.format.name + ' for ' + item.channel.name + ')</p>' +
                '<p><input type="checkbox"';
        if (item.done !== null) {
            html += "checked"
        };
        html += '></p>';
        html += '<pre data-bind="text: $root"></pre>';  // http://www.knockmeout.net/2013/06/knockout-debugging-strategies-plugin.html
        return html;
    }
}

所有数据绑定(bind)都经过测试并且正常,但我想不出一种方法将 knockout 行为附加到 vis.js 时间线库生成的模板。正如您所看到的,即使尝试打印 $root 数据也无济于事。

如何将可观察量附加到此模板?

最佳答案

如果您愿意,时间轴组件选项的模板属性允许您提供 HTML 元素而不是 HTML 字符串。这可能是实现您所追求的目标的一种方法。通过这种方式,您可以创建元素,使用 Knockout 使用提供的项目作为上下文在元素(及其子元素)上应用绑定(bind),并将该元素返回到 vis.js。

执行此操作的示例可以使用类似于以下的代码:

var templateHtml = '<div data-bind="text: content"></div>'
//Set the template to a custom template which lets knokcout bind the items
options.template = function(item){
    //Create a div wrapper element to easily create elements from the template HTML
    var element = document.createElement('div');
    element.innerHTML = templateHtml;
    //Let knockout apply bindings on the element with the template, using the item as data context
    ko.applyBindings(item, element);
    //Return the bound element to vis.js, for adding in the component
    return element;
};

在 knockout 世界中,为 vis.js 时间轴组件创建自定义的 bindingHandler 当然会更好。

因此,这里还有一个使用自定义绑定(bind)处理程序进行 knockout 的类似示例(这是一个非常简单的示例绑定(bind)处理程序,并不真正支持数据的可观察选项或可观察数组,但它确实支持项目中的可观察值)。

ko.bindingHandlers.visTimeline = {
    init: function(element, valueAccessor){
        var unwrappedValue = ko.unwrap(valueAccessor());
        var data = ko.unwrap(unwrappedValue.data);
        var options = ko.unwrap(unwrappedValue.options);
    
        if (options.templateId){
            var templateId = ko.unwrap(options.templateId);
            var templateHtml = document.getElementById(templateId).innerHTML;
            //Set the template to a custom template which lets knokcout bind the items
            options.template = function(item){
                //Create a div wrapper element to easily create elements from the template HTML
                var element = document.createElement('div');
                element.innerHTML = templateHtml;
                //Let knockout apply bindings on the element with the template, using the item as data context
                ko.applyBindings(item, element);
                //Return the bound element to vis.js, for adding in the component
                return element;
            };
        }

        //Apply the vis.js timeline component
        new vis.Timeline(element, data, options);
        //Let knockout know that we want to handle bindings for child items manually
        return { controlsDescendantBindings: true };
    }
};

var items = [
    { id: 1, content: 'item 1', counter: ko.observable(0), start: '2014-04-20'},
    { id: 2, content: 'item 2', counter: ko.observable(0), start: '2014-04-14'},
    { id: 3, content: 'item 3', counter: ko.observable(0), start: '2014-04-18'},
    { id: 4, content: 'item 4', counter: ko.observable(0), start: '2014-04-16', end: '2014-04-19'}
];

var viewModel = {
    items: items
};

//Randomly increment the counters of the items, to see that the data is bound
setInterval(function(){
    var randomItem = items[Math.floor(Math.random() * items.length)];
    randomItem.counter(randomItem.counter() + 1);
}, 500);

ko.applyBindings(viewModel);
<!-- First, let's include vis.js and knockout -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/vis/3.12.0/vis.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vis/3.12.0/vis.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>

<!-- This is the template we want to use for our items -->
<script type="text/html" id="myCustomTemplate">
    <strong data-bind="text: id"></strong>. <span data-bind="text: content"></span>
    <div data-bind="text: counter"></div>
</script>

<!-- And this is where we use our bindingHandler -->
<div data-bind="visTimeline: { data: items, options: { templateId: 'myCustomTemplate' } }"></div>

您还可以在 http://jsbin.com/lecidaxobo/1/edit?html,js,output 处看到此片段

关于javascript - 将 Knockout.js 与自定义模板引擎结合使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29607214/

相关文章:

javascript - Babel 创建输出目录但不转译任何文件

即使呈现 jquery 模板,knockout.js 也会调用 click

javascript - 在 KnockoutJs 中对可观察数组进行排序时 UI 未更新

javascript - vis.js 中的自定义边缘绘制函数

javascript - Font-Awesome 在 IE8 中渲染不一致

javascript - Webpack - 动态导入类

javascript - 为什么这个 javascript 会抛出这个特定的错误?

javascript - Knockout.js removeAll 函数不起作用

javascript - 获取我选择的节点的 id

javascript - vis.js 创建多行标题