var tv = new EasyTreeview({
el: 'tree',
draggable: true,
checkable: true,
onClick: function (symbol, node) {
// console.log('%o %o', symbol, node)
},
onDragged: function (symbol, node) {
// console.log('%o %o', symbol, node)
},
onDropped: function (symbol, node) {
// console.log('%o %o', symbol, node)
},
onChecked: function (symbol, node, symbols) {
// console.log('%o %o %o', symbol, node, symbols)
},
onUnchecked: function (symbol, node, symbols) {
// console.log('%o %o %o', symbol, node, symbols)
},
data: [
{
id: 0,
text: '服装',
children: [
{
id: 4,
text: '男装'
}, {
id: 6,
text: '女装',
style: {
color: '#e33',
lineHeight: '21px'
},
children: [
{
id: 12,
text: '裤子',
style: {
color: '#fff',
backgroundColor: '#bbdefb'
}
}, {
id: 13,
text: '裙子',
checked: true,
on: {
click: function (e) {
console.log(e.target)
}
}
}
]
}
]
}
]
})
DOM 已有节点,用以作为 树形控件的容器。如果该节点不存在,控件将不会被创建。
如果值为 true, 树节点将可被拖拽。
如果值为 true, 树节点将包含复选框且可被选中。
用以创建树结构的用户数据。
树节点的文本内容。
自定义的节点样式。
自定义的节点事件监听。
当前节点的下属子树。
symbol, 系统分配的序列号
node, 根据节点数据打包的系统对象
当树节点被点击时触发。
当树节点被拖拽时触发。 (树控件 draggable 应为 true).
当被拖拽节点被丢到该节点时触发。 (树控件 draggable 应为 true).
PS: 参数 node 不是被拖拽节点,而是被丢上的节点。
symbols, 所有已选中的节点标号
当树节点被选中时触发。 (树控件 checkable 应为 true).
当树节点被取消选中状态时触发。 (树控件 checkable 应为 true).
获取系统封装的所有节点对象
获取被选中的系统封装的所有节点对象
获取原始数据当前的树形结构。这在拖拽树节点,树形结构发生变化时尤其有用。
如果需要改变树控件的整体风格样式,这里并不建议在节点数据中挨个配置样式属性,而是希望引用者重写并覆盖树节点当前的类样式。
控件的 DOM 结构如下:
-
节点
有些时候,开发者也许并不清楚自己创建到底是一颗树,还是一个森林。一般情况下,这两者的区别对业务并没有任何影响,因此也无需做差异化处理。然而在这里,如果你创建的是一个森林,那么请不要轻易改变根节点的性质,因为当你将它变为一截枝干时,它便无法再长成为一颗树了。
在树控件的处理中,循环和递归结构必不可少,递归用以纵向处理树的深度,循环用以横向处理树的广度。
我们可以使用 ul 标签建立子树增加树深,使用 li 标签建立树的节点以增加树宽,这在上文 DOM 结构中可以看到。下面是 dom 创建函数的 简单原型:
var createBranch = function (nodes) {
// self func, createElement
var ul = createElement('ul', {
className: 'sub-tree'
})
// loop
nodes.forEach(function (node) {
var li = createElement('li', {
className: 'branch-node'
})
if (node.children) {
// recurse
li.appendChild(createBranch(node.children))
}
ul.appendChild(li)
})
return ul
}
在这里,children 起到两个作用:
在控件创建时,树节点状态(用户可控:checked,collasped,系统记录:branched)是可初始化的;而在用户 选中/不选中 复选框、收缩/展开 子树、拖拽移动树节点 时,对应的 checked、collapsed、branched 状态值 也是需要切换的。虽是同一属性,却有两套业务要处理。面对这种情况,这里将 初始获取属性值和将属性值赋给 DOM 节点 解耦,用户事件刷新属性值和将属性值同步给视图解耦,以实现业务流程最大程度上的松散和可复用。
业务流程:
这样处理,不仅使 代码的可读性和可维护性 更加良好,也解决了功能上的一大痛点:
在循环创建树节点时,如何根据当前节点的 checked 属性同步其父子节点的 checked 属性 (在得到它的 checked 属性时, 它的 父子节点可能尚未创建完毕)。
作为一款轻量级树形控件,EasyTreeview 旨在解决常用业务场景,并没有过度拓展,也没有引入任何外部静态资源。代码结构并不复杂,且对其它功能(如动态增删树节点等)也做了可拓展性的支持,如有其它需求,请及时反馈或自行拓展。
GitHub
码云
最后, 欢迎各路大神前来 Hack,也希望感兴趣者能够加入并成为项目的 contributor。