在现代Web开发中,MVVM(Model-View-ViewModel)模式是一种非常流行的架构模式,它帮助开发者创建丰富、响应式的显示和编辑用户界面,同时保持清晰的数据模型。用户不需要担心将数据模型绑定到视图上,因为任何时候数据发生变化,视图都会自动刷新。
在进行一个项目时,被要求创建一个多选框。考虑到正在使用Knockout.js,想到了创建一个自定义绑定处理器,以便可以重复使用代码。
以下是HTML代码:
<select id="customID" data-bind="Values: ViewModelPropertyName">
<option value="1">value1</option>
<option value="2">value2</option>
<option value="3">value3</option>
<option value="4">value4</option>
</select>
<img id="imgcustomID" src="../add.png"/><br/>
<ul id="ulcustomID" class="navlist"></ul>
以下是CSS样式:
.navlist {
margin-left: 0;
padding-left: 0;
list-style: none;
}
.navlist li {
padding-left: 25px;
background-image: url(../images/minus.png);
background-repeat: no-repeat;
background-position: 0 .1em;
height: 16px;
}
以下是JavaScript代码:
<script type="text/javascript">
ko.bindingHandlers.Values = {
init: function (element, valueAccessor) {
var _this = ko.bindingHandlers.Values;
var id = jQuery(element).attr('id');
jQuery(element).after("<img src='../../../images/add.png' id='img" + id + "' onClick='javascript: ko.bindingHandlers.Values.setCommand(\"" + id.toString() + "\");'></img><ul class='navlist' id='ul" + id + "'></ul>");
var values = new Array();
var value = ko.utils.unwrapObservable(valueAccessor());
if (value) {
values[0] = value;
if (values[0] == "")
values.splice(0, 1);
setTimeout("ko.bindingHandlers.Values.addLI('" + id + "','" + values + "',0);", 300);
}
},
setCommand: function (id) {
var _this = ko.bindingHandlers.Values;
if (jQuery('#' + id).attr('value') !== "") {
var select = document.getElementById(id);
if (select.selectedIndex >= 0)
_this.addLI(id, select.options[select.selectedIndex].value, 1);
}
},
addLI: function (id, values, mode) {
var _this = ko.bindingHandlers.Values;
var currentvalues = [];
var prop = id.replace("slct", "");
var viewModelData = JSON.parse(ko.toJSON(viewModel));
if (viewModelData[prop]) {
if (viewModelData[prop].toString().search(",") !== -1) {
var currentvalues = eval("viewModel." + prop + "().split(',')");
}
else {
currentvalues[0] = eval("viewModel." + prop + "()");
}
if (currentvalues[0] == "")
currentvalues.splice(0, 1);
if (values !== "" && mode == 1)
currentvalues.pushIfNotExist(values);
eval("viewModel." + prop + "('" + currentvalues.join(',') + "')");
}
else {
eval("viewModel." + prop + "(" + values + ")");
}
if (mode == 0) {
jQuery.each(currentvalues, function (key, value) {
var li = document.createElement('li');
var select = document.getElementById(id);
li.innerHTML = _this.getText(id, value.trim());
li.customValue = value;
var ul = document.getElementById('ul' + id);
li.onclick = function () {
var option = document.createElement('option');
option.text = this.innerHTML;
option.value = this.customValue;
select.add(option);
ul.removeChild(li);
eval("viewModel." + prop + "(_this.getValues('" + id + "'))");
};
ul.appendChild(li);
_this.removeOption(id, value.trim());
});
}
else {
var li = document.createElement('li');
var select = document.getElementById(id);
li.innerHTML = _this.getText(id, values);
li.customValue = values;
var ul = document.getElementById('ul' + id);
li.onclick = function () {
var option = document.createElement('option');
option.text = this.innerHTML;
option.value = this.customValue;
select.add(option);
ul.removeChild(li);
eval("viewModel." + prop + "(_this.getValues('" + id + "'))");
};
ul.appendChild(li);
_this.removeOption(id, values);
}
},
getValues: function (id) {
return jQuery('#ul' + id + ' li').map(function () {
return jQuery(this).attr('customValue');
}).get().join(", ");
},
getText: function (id, value) {
return jQuery("#" + id + " option[value='" + value + "']").text();
},
removeOption: function (id, value) {
jQuery("#" + id + " option[value='" + value + "']").remove();
}
};
var viewModel = {};
viewModel.ViewModelPropertyName = '1,2';
ko.applyBindings(viewModel);
</script>
请确保将add.png和minus.png图片添加到images文件夹中,并确保它们可以从CSS和HTML文件中访问。