先说下思路: 从0搭建的话,需要先考虑下面这些问题:
HTML结构:首先在HTML中创建一个容器,用于包含整个树控件的结构。可以使用div 和备注不同的class名来表示树的层级结构。每个列表项中可以包含一个展开/折叠的图标、一个节点名称等元素。
CSS样式:添加样式来美化树控件。可以使用CSS选择器来选择各个元素,并设置宽度、高度、颜色、边框等属性。还可以添加js函数来添加class来设置展开/折叠图标的样式。
JavaScript逻辑:使用JavaScript编写树控件的逻辑。需要实现以下功能:
树的数据结构:定义一个代表树的数据结构,可以使用对象、数组等来表示节点之间的层级关系。初始化及渲染:在页面加载时,通过JavaScript将树的数据结构生成树的DOM结构,并进行初始化渲染。可以根据需要设置初始展开状态、选中状态等。
添加事件监听器:为树的各个交互元素(展开/折叠图标)添加事件监听器,以便响应用户的操作,并更新相关的数据和DOM元素
根据需要进行样式和功能的优化:依据实际需求,对树控件进行样式和功能上的优化,如添加动画效果、优化性能等
示例图片:
现在开始上代码:
css部分:
.tree-img{
width: 14px;
}
.tree-ul{
padding-left: 30px;
margin: 0;
}
.tree-li-info a{
display: block;
margin-right: 4px;
}
.img-a{
width: 14px;
height: 14px;
background-image: url(data:image/png;base64,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);
background-repeat: no-repeat;
background-color: transparent;
background-size: cover; /* 缩放背景图片以覆盖容器 */
}
.tree-li-info{
width: 100%;
display: inline-flex;
align-items: center;
color: #555;
line-height: 22px;
font-size: 14px;
}
.tree-li-info:hover{
background-color: #eee;
}
.no-expand-img{
transform:rotate(-90deg);
}
.expand-img{
transform:rotate(0deg)
}
.no-expand{
display: none;
}
.expand{
display: block;
}
.selected{
background-color: #eee;
}
html部分
<div class="tree" id="tree">
<div id="div"></div>
</div>
js部分
const list=[{'name':'李四','child':[{'name':'王五'},{'name':'张三','child':[{'name':'王五'},{'name':'张三','child':[{'name':'王五'},{'name':'张三'}]}]}]},{'name':'王五','child':[{'name':'王五'},{'name':'张三'}]}]
let div=document.getElementById('div');
function generateNestedList(data,field,level,callback) {
let treeUl = document.createElement('div');
treeUl.classList.add('tree-ul');
if (level > 0) {
treeUl.classList.add('no-expand');
}
data.forEach(item => {
let treeLi = document.createElement('div');
treeLi.classList.add('tree-li');
let treeLiInfo = document.createElement('div');
treeLiInfo.classList.add('tree-li-info');
treeLiInfo.setAttribute('data-level', level);
treeLiInfo.addEventListener("click", function(event) {
callback(item,level)
})
if (item.child && item.child.length > 0) {
let imgA = document.createElement('a');
imgA.classList.add('img-a');
imgA.classList.add('no-expand-img');
treeLiInfo.appendChild(imgA);
}
let nameA = document.createElement('a');
nameA.textContent = item[field];
treeLiInfo.appendChild(nameA);
treeLi.appendChild(treeLiInfo);
if (item.child && item.child.length > 0) {
let childTreeUl = generateNestedList(item.child,field, level + 1,callback);
treeLi.appendChild(childTreeUl);
}
treeUl.appendChild(treeLi);
});
return treeUl;
}
// function generateNestedList(data,level) {
// let result='';
// if(level>0){
// result+= '<div class="tree-ul no-expand">';
// }else{
// result+= '<div class="tree-ul ">';
// }
// data.forEach(item => {
// result += '<div class="tree-li">';
// result += '<div class="tree-li-info" data-level='+level+'>';
// if (item.child && item.child.length > 0) {
// result+=' <a class="img-a no-expand-img"></a>';
// }
// // result += ' <input type="checkbox" />'
// result += ' <a>'+item.name+'</a>'
// result += '</div>';
// if (item.child && item.child.length > 0) {
// result += generateNestedList(item.child,level+1);
// }
// result += '</div>';
// });
// result += '</div>';
// return result;
// }
function clickNode(item,level){
console.log('点击了',item,'层级是',level)
}
//开始渲染
const nestedList = generateNestedList(list,'name',0,clickNode);
div.appendChild(nestedList);
const listItem = document.querySelectorAll(".img-a");
listItem.forEach(function(item) {
item.addEventListener("click", function(event) {
event.stopPropagation();
if(item.classList.contains("no-expand-img")){
item.classList.remove("no-expand-img");
item.classList.add("expand-img")
}else{
item.classList.remove("expand-img");
item.classList.add("no-expand-img")
}
expand(item);
});
});
function expand(e){
let node=e.parentNode.parentNode;
const childNodes = Array.from(node.childNodes);
childNodes.forEach(node => {
if(node.classList.contains('tree-ul')){
if(node.classList.contains("no-expand")){
node.classList.remove("no-expand");
node.classList.add("expand")
}else{
node.classList.remove("expand");
node.classList.add("no-expand")
}
}
});
}
const liItemsDiv = document.querySelectorAll('.tree-li-info');
// 为每个 <li> 元素添加事件监听器
liItemsDiv.forEach((div) => {
div.addEventListener('click', function(event) {
// 移除所有的 selected 类名
liItemsDiv.forEach((item) => {
item.classList.remove('selected');
});
div.classList.add('selected');
});
});