简介
很多时候,当你需要新建节点时,并不仅仅只需要个节点的名称,你会需要一系列的数据属性,这时候 zTree 提供的 input 输入框就绝对无法满足你的需求,本篇将全面讲解如何让新增按钮配合 zTree 外面的表单实现这种功能。
看这篇文档时,你需要对照 API 文档进行学习(http://www.treejs.cn/v3/api.php)
css
这是 demo,只是实现功能,所以只显示简单的表单,不会做什么美化的样式处理
表单图层具体显示位置请自行处理,可以在 树旁边 显示,也可以做成浮动图层显示
// 新增按钮的样式
.ztree li span.button.add {
margin-left: 2px;
margin-right: -1px;
background-position: -144px 0;
vertical-align: top;
*vertical-align: middle
}
// demo 界面简单样式
# ztree-layer {
margin: 0 auto;
width: 500px;
}
# new-node-layer {
display: none;
position: absolute;
width: 300px;
height: 150px;
top: 100px;
left: 50%;
margin-left: -150px;
background-color: #ffffff;
border: 1px solid silver;
box-shadow: 0 0 5px #1E1E1E;
text-align: center;
padding: 30px;
}
# new-node-layer div {
margin: 20px;
}
body 内的HTML
<div id="ztree-layer">
<ul id="treeDemo" class="ztree"></ul>
</div>
<!-- Demo 使用的简单表单,你可以使用外面的表单组件,也可以制作自己需要的表单结构 -->
<div id="new-node-layer">
<div>
名称:<input id="nodeName" name="nodeName">
</div>
<div>
简介:<input id="nodeInfo" name="nodeInfo">
</div>
<div>
<button type="button" onclick="submitNewNode()">确定</button>
<button type="button" onclick="hideForm()">取消</button>
</div>
</div>
js 代码
var setting = {
view: {
addHoverDom: addHoverDom,
removeHoverDom: removeHoverDom,
selectedMulti: false
},
edit: {
enable: true,
editNameSelectAll: true
},
data: {
simpleData: {
enable: true
}
},
callback: {
beforeDrag: beforeDrag,
beforeEditName: beforeEditName,
onRemove: onRemove
}
};
var zNodes = [
{id: 1, pId: 0, name: "父节点 1", open: true},
{id: 11, pId: 1, name: "叶子节点 1-1"},
{id: 12, pId: 1, name: "叶子节点 1-2"},
{id: 13, pId: 1, name: "叶子节点 1-3"},
{id: 2, pId: 0, name: "父节点 2", open: true},
{id: 21, pId: 2, name: "叶子节点 2-1"},
{id: 22, pId: 2, name: "叶子节点 2-2"},
{id: 23, pId: 2, name: "叶子节点 2-3"},
{id: 3, pId: 0, name: "父节点 3", open: true},
{id: 31, pId: 3, name: "叶子节点 3-1"},
{id: 32, pId: 3, name: "叶子节点 3-2"},
{id: 33, pId: 3, name: "叶子节点 3-3"}
];
// Demo 中禁止拖拽操作
function beforeDrag(treeId, treeNodes) {
return false;
}
// 让表单同时具有编辑节点的功能
// 利用 beforeEditName 回调函数,关闭 zTree 默认编辑功能,同时显示表单
function beforeEditName(treeId, treeNode) {
zTreeObj.selectNode(treeNode);
showForm(treeNode, false);
return false;
}
// 删除节点时,如果是正在编辑的节点,就直接隐藏表单
function onRemove(e, treeId, treeNode) {
if (newNodeLayer.curNode == treeNode) {
hideForm();
}
}
// 新增按钮的处理,这部分与前两篇文章基本一样,有区别的地方主要在 click 事件中
var newCount = 1;
function addHoverDom(treeId, treeNode) {
var sObj = $("#" + treeNode.tId + "_span");
if (treeNode.editNameFlag || $("#addBtn_" + treeNode.tId).length > 0) return;
var addStr = "<span class='button add' id='addBtn_" + treeNode.tId
+ "' title='add node' onfocus='this.blur();'></span>";
sObj.after(addStr);
var btn = $("#addBtn_" + treeNode.tId);
if (btn) {
btn.bind("click", function () {
// 选中当前父节点
zTreeObj.selectNode(treeNode);
// 显示表单
showForm(treeNode, true);
return false;
});
}
}
// 移除新增按钮
function removeHoverDom(treeId, treeNode) {
$("#addBtn_" + treeNode.tId).unbind().remove();
}
// 表单提交
function submitNewNode() {
var nodeName = nodeNameObj.val();
var nodeInfo = nodeInfoObj.val();
// 数据校验
if (nodeName.length === 0) {
alert('名称不允许为空!');
return;
}
// 这里采用 setTimeout 模拟 ajax 的异步功能,
// 延迟 2 秒后处理界面上的 新增、编辑操作
// 实际应用中,肯定还要考虑 服务端处理数据出错的情况,
// 出错后就不应该在界面上 新增、编辑了
setTimeout(function() {
if (newNodeLayer.addNode) {
// 新增节点操作
zTreeObj.addNodes(newNodeLayer.curNode, {
id: (100 + newCount),
pId: newNodeLayer.curNode.id,
name: nodeName,
info: nodeInfo
});
} else {
// 编辑节点操作
newNodeLayer.curNode.name = nodeName;
newNodeLayer.curNode.info = nodeInfo;
zTreeObj.updateNode(newNodeLayer.curNode);
}
// 保存后,隐藏表单
hideForm();
}, 2000);
}
// 隐藏表单
function hideForm() {
newNodeLayer.hide();
}
// 显示表单
function showForm(treeNode, addNode) {
treeNode = treeNode || {};
newNodeLayer.curNode = treeNode;
newNodeLayer.addNode = !!addNode;
if (!newNodeLayer.addNode) {
nodeNameObj.val(treeNode.name || '');
nodeInfoObj.val(treeNode.info || '');
}
newNodeLayer.show();
nodeNameObj.get(0).focus();
}
// 页面加载后初始化 zTree
var zTreeObj, newNodeLayer, nodeNameObj, nodeInfoObj;
$(document).ready(function () {
zTreeObj = $.fn.zTree.init($("#treeDemo"), setting, zNodes);
newNodeLayer = $('#new-node-layer');
nodeNameObj = $('#nodeName');
nodeInfoObj = $('#nodeInfo');
});
因为 Demo 无法真正模拟在服务端保存数据库,所以这里使用 setTimeout 去模拟 ajax 的异步过程,请一定要注意。 Demo 中采用的是一次性加载的数据,当你换成异步加载时,你会发现给没有展开的父节点添加子节点后,新节点出现了两个,这是为什么呢?请看下一篇:7.06 为什么异步加载时,新增节点后会出现重复的节点