将 knockout.js 与自定义模板引擎一起使用
Using knockout.js with custom template engine
我正在尝试让 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;
}
}
所有数据绑定都经过测试并且正常,但我想不出一种方法可以将敲除行为附加到 vis.js 时间线库生成的模板。如您所见,即使尝试打印出 $root 数据也无济于事。
如何将可观察对象附加到此模板?
如果您愿意,时间轴组件选项的模板 属性 允许您提供 HTML 元素而不是 HTML 字符串。这可能是实现您所追求目标的一种方式。通过这种方式,您可以创建元素,使用 knockout 将提供的项目用作上下文并将该元素 return 应用于元素(及其子元素)上的绑定 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;
};
在淘汰赛世界中,为 vis.js 时间轴组件创建自定义绑定处理程序 当然 更好。
因此,这里您还有一个使用自定义 bindingHandler 进行淘汰的示例(这是一个非常简单的示例 bindingHandler,并不真正支持数据的可观察选项或 observableArray,但它确实支持项目中的可观察值).
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>
中查看此片段
我正在尝试让 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;
}
}
所有数据绑定都经过测试并且正常,但我想不出一种方法可以将敲除行为附加到 vis.js 时间线库生成的模板。如您所见,即使尝试打印出 $root 数据也无济于事。
如何将可观察对象附加到此模板?
如果您愿意,时间轴组件选项的模板 属性 允许您提供 HTML 元素而不是 HTML 字符串。这可能是实现您所追求目标的一种方式。通过这种方式,您可以创建元素,使用 knockout 将提供的项目用作上下文并将该元素 return 应用于元素(及其子元素)上的绑定 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;
};
在淘汰赛世界中,为 vis.js 时间轴组件创建自定义绑定处理程序 当然 更好。
因此,这里您还有一个使用自定义 bindingHandler 进行淘汰的示例(这是一个非常简单的示例 bindingHandler,并不真正支持数据的可观察选项或 observableArray,但它确实支持项目中的可观察值).
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>