knockout已经使用一段时间了,但真正感觉到一些东西了,还是从下面这个例子开始的。不需要直接操作dom,有个绑定(当然是双向的)即可,将数据和dom元素联系起来,免去了在定位dom。
一个tree树的例子,带有复选框、删除节点及重命名功能。
效果图:
可以从这里查看 演示效果
Css代码
<script type='text/javascript' src='http://www.see-source.com/js/knockout-2.2.0.js'></script>
<style type="text/css">
li {list-style:none; font-size:14px;}
ul {padding-left:25px;}
.operaterDiv{width:100px; margin-left:100px;; z-index:100px;position:absolute;margin-top:-5px; border:1px solid #000;background-color:#FFF}
.operaterDiv li{list-style-type:none; padding:1px; margin-left:20px;}
.operaterDiv a:link {text-decoration: underline; color:blue;}
.operaterDiv a:visited{text-decoration: underline;; color:blue;}
.operaterDiv a:hover {text-decoration: none; color:blue;}
.close{float:right; font-size:5px; color:red;}
.highLight{background-color:#009; color:#FFF;}
</style>
Html代码
<ul data-bind="template: { name: 'guideTmpl', foreach: menus}"></ul><br/>
<a href="javascript:void(0)" onClick="getSelectedValues()">查看选中值</a><br/>
Js代码
<!--节点模板模板-->
<script id="guideTmpl" type="text/html">
<li>
<img data-bind="attr: {src:imageUrl}, click:$root.openOrClose"/>
<input type="checkbox" data-bind="checked:selected"/>
<span data-bind="text: name, visible:switchS, css:{highLight:editOpened}, event:{contextmenu:$root.myContextmenu, click:$root.openOrClose}, clickBubble: false"></span>
<span data-bind="visible:!switchS()"><input type="text" data-bind="value:name,event:{blur:$root.closeAllOpenedDiv}"/></span>
<div data-bind="visible: editOpened" class="operaterDiv">
<span class="close" data-bind="click:$root.closeOpenedDiv">关闭</span>
<ul style="padding:0;margin:0; margin-top:5px;">
<li><a href="#" data-bind="click:function(){if(confirm('确定要删除吗?')){$parent.children.remove(this)}; this.editOpened(false);}, clickBubble: false">Delete</a></li>
<li><a href="#" data-bind="click:$root.doSwitch, clickBubble: false">Rename</a></li>
</ul>
</div>
<ul data-bind="template: { name: 'guideTmpl', foreach: children }, visible:opened"></ul>
</li>
</script>
<script type="text/javascript">
var index = 1;//用于模拟value值(实际中应是每个节点的唯一标识)
var Menu = function(name, children, opened, imageUrl, selected, value) {//节点对应的js对象
this.name = ko.observable(name);
this.children = ko.observableArray(children || []); //下级子节点
this.opened = ko.observable(opened); //true:展开 false:折叠
this.imageUrl = ko.observable("http://www.dhtmlgoodies.com/scripts/drag-drop-folder-tree/images/dhtmlgoodies_plus.gif"); //true:展开 false:折叠
this.selected = ko.observable(false);
this.value = "000" + index++;
this.editOpened = ko.observable(false);
this.switchS = ko.observable(true);
};
var MenuModel = function() {
var self = this;
self.menus = ko.observableArray([
new Menu("Twitter BootStrap", [
new Menu("bootstrap介绍", [new Menu("2222")]),
new Menu("响应式设计"),
new Menu("JavaScript插件")
]),
new Menu("Knockout", [
new Menu("监控属性(Observables)"),
new Menu("控制流绑定(Control flow)"),
new Menu("表单域绑定(Form fields)"),
new Menu("自定义绑定(Custom)")
])
]);
//展开、折叠操作
self.openOrClose = function(source){
self.closeAllOpenedDiv();
var opened = source.opened();
if(source.children() == 0)
return ;
if(opened){
source.opened(false);
source.imageUrl("http://www.dhtmlgoodies.com/scripts/drag-drop-folder-tree/images/dhtmlgoodies_plus.gif");
}else{
source.opened(true);
source.imageUrl("http://www.dhtmlgoodies.com/scripts/drag-drop-folder-tree/images/dhtmlgoodies_minus.gif");
}
var children = source.children();
for (var i in children){
if(children[i].children().length == 0 ){//存在子节
children[i].imageUrl("http://www.see-source.com/images/dhtmlgoodies_white.gif");
}
}
};
//获得复选框所有选中的value值
self.selectedValues = function(){
var valuesStr = "";
var menus = self.menus();
for (var i in menus){
if(menus[i].selected()){
valuesStr += ",";
valuesStr += menus[i].value;
}
var qiantao = function(child){
for (var i in child){
if(child[i].selected()){
valuesStr += ",";
valuesStr += child[i].value;
}
qiantao(child[i].children());
}
}
qiantao(menus[i].children());
}
return valuesStr;
};
//右键事件(弹出操作层)
self.myContextmenu = function(source){
self.closeAllOpenedDiv();
source.editOpened(true);
};
//切换
self.doSwitch = function(source){
source.switchS(false);
source.editOpened(false);
};
//关闭所有弹出操作层
self.closeAllOpenedDiv = function(){
var menus = self.menus();
for (var i in menus){
var qiantao = function(child){
for (var i in child){
child[i].editOpened(false);
child[i].switchS(true);
qiantao(child[i].children());
}
}
qiantao(menus[i].children());
menus[i].editOpened(false);
menus[i].switchS(true);
}
};
//关闭当前弹出操作层
this.closeOpenedDiv = function(source){
source.editOpened(false);
}
};
var myMenuModel = new MenuModel();
ko.applyBindings(myMenuModel);
var children = myMenuModel.menus();
for (var i in children){
if(children[i].children().length == 0 ){//存在子节
children[i].imageUrl("http://www.see-source.com/images/dhtmlgoodies_white.gif");
}
}
</script>
<script type="text/javascript">
function getSelectedValues(){ //查看选中的值列表
var values = myMenuModel.selectedValues();
if(values.length != 0){
values = values.substring(1);
}
alert(values);
}
</script>
以上代码可直接粘贴运行。