我有一个使用Knockout构建的可编辑网格,它遵循所讨论的网格线here。
我希望为hasfocus
分配一个计算的可观察对象(与在上述链接帖子上完成的内容相反,其中hasfocus
绑定分配了相同的内容可观察为visible
),但它不起作用 - 编辑的元素没有被聚焦。
这是我的代码(这里是fiddle):
$(document).ready(function() {
var viewModel = new Grid.ViewModel();
viewModel.init();
ko.applyBindings(viewModel);
});
ko.bindingHandlers.clickToEdit = {
init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
if (element.className == "editable") {
var observable = valueAccessor();
span = document.createElement("span");
var input = document.createElement("input");
element.appendChild(span);
element.appendChild(input);
ko.applyBindingsToNode(span, {
text: observable,
visible: ko.computed(function() { return !viewModel.isEditState(); }),
});
ko.applyBindingsToNode(input, {
value: observable,
visible: viewModel.isEditState,
hasfocus: viewModel.shouldFocus, // this seems to not work (but it works if we assign it with isEditState)
});
}
},
}
var Grid = {
RowViewModel: function() {
var self = this;
self.district = ko.observable();
self.team = ko.observable();
self.factory = ko.observable();
self.isEditState = ko.observable(false);
self.shouldFocus = ko.computed(function() {
return self.isEditState();
});
self.init = function (data) {
self.district(data.District);
self.team(data.Team);
self.factory(data.Factory);
}
self.setEditState = function(){
self.isEditState(!self.isEditState());
}
},
ViewModel: function() {
var self = this;
self.data = ko.observableArray();
self.init = function() {
var data = self.getData();
self.data(data);
}
self.getData = function() {
var data = [];
var rows = [
{ District: "North", Team: "Jim", Factory: "Mars" },
{ District: "South", Team: "John", Factory: "Pluto" },
];
rows.forEach(function (element, index) {
var row = new Grid.RowViewModel();
row.init(element);
data.push(row);
});
return data;
}
},
}

td, tr > th {
text-align: center;
vertical-align: middle;
}
a {
text-decoration: none !important;
}
input {
width: 100%;
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div class="grid-container">
<table class="table table-bordered table-condensed" style="table-layout:fixed">
<thead>
<tr class="active">
<th></th>
<th>District</th>
<th>Team</th>
<th>Factory</th>
<th>Action</th>
</tr>
</thead>
<tbody data-bind="foreach: data">
<tr>
<td>
<input type="checkbox" />
</td>
<td data-bind="text: district, clickToEdit: district"></td>
<td class="editable" data-bind="clickToEdit: team"></td>
<td data-bind="text: factory, clickToEdit: factory"></td>
<td>
<a href="#" data-bind="visible: !isEditState(), click: setEditState">
<i class="glyphicon glyphicon-pencil"></i>
</a>
<a href="#" data-bind="visible: isEditState(), click: setEditState">
<i class="glyphicon glyphicon-ok"></i>
</a>
</td>
</tr>
</tbody>
</table>
</div>
&#13;
感兴趣的行是:
self.shouldFocus = ko.computed(function() {
return self.isEditState();
});
注意:虽然我在这里仅使用self.isEditState()
,但我实际上使用了一两个表达式,因此需要使用computed
。
答案 0 :(得分:2)
在我建议解决方案之前,我想向您展示minimal, complete, and verifiable example问题。注意看看发生了什么变得容易多了?
const vm = {};
vm.visible = ko.observable(false);
vm.hasFocus = ko.computed(vm.visible);
vm.toggle = () => vm.visible(!vm.visible());
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<input data-bind="visible: visible, hasFocus: hasFocus">
<button data-bind="click: toggle">toggle</button>
从这次重建中我发现:问题可能是一次处理visible
和hasFocus
更新,而不是给DOM足够的时间来处理它们?毕竟,浏览器无法将焦点添加到隐藏元素......
让我们尝试制作hasFocus
计算deferred
。延迟计算在事件循环结束时运行,有点像setImmediate(cb)
或setTimeout(cb, 0)
。
const vm = {};
vm.visible = ko.observable(false);
vm.hasFocus = ko.computed(vm.visible)
.extend({ deferred: true });
vm.toggle = () => vm.visible(!vm.visible());
ko.applyBindings(vm);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<input data-bind="visible: visible, hasFocus: hasFocus">
<button data-bind="click: toggle">toggle</button>
成功!现在,knockout会更新输入的可见性,为DOM提供更新时间,只会添加焦点。
答案 1 :(得分:0)
将您的computed
更改为pureComputed
,它会有效。
您可以看到纯函数指南here
self.shouldFocus = ko.pureComputed(function() {
return self.isEditState();
});