纯js,编写树形结构
先看下效果图

直接上代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="container">
</div>
</body>
<style>
.containerParent {
display: flex;
flex-direction: column;
width: auto;
}
.containerChildren {
margin-left: 15px;
width: 300px;
border-left-style: dotted;
border-color: #D8D8D8;
}
.parentChild {
width: 300px;
}
.operaion_row-button {
display: inline-block;
min-width: 50px;
}
.editContainer {
display: inline-block;
padding-left: 10px;
padding-right: 10px;
width: 100px;
height: 20px;
max-width: 100px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap
}
.editContainer:focus {
color: goldenrod;
}
.Icon_class {
width: 15px;
height: 15px;
}
.parentIcon {
margin-left: 10px;
}
.parent_span {
margin-left: 10px;
}
.descriter {
display: inline-block;
margin-top: -3px;
color: #D8D8D8;
vertical-align: top;
}
.focusClass {
color: blue;
}
</style>
<script>
// 源数据
const data = [
{
id: 1,
name: "高配室",
spread: true,
tempChildren: [],
children: [
{
id: 2,
name: "第一个子节点",
edit: false,
checked: false,
children: [
{
id: 8,
edit: false,
checked: false,
name: "孙子节点",
children: []
},
]
},
{
id: 5,
name: "第二个子节点",
checked: false,
edit: false,
children: []
},
]
}
];
// 收集数据
const arrId = [];
// 切换子树中的显示状态
function toggleFnc(val) {
data.map(currentData => {
if (currentData.id == val) {
let temCuttentchildren = currentData.children;
let temCuttenttempChildren = currentData.tempChildren;
currentData.children = temCuttenttempChildren
currentData.tempChildren = temCuttentchildren;
currentData.spread = !currentData.spread
}
})
container.innerHTML = getParent(data);
};
// 切换选中状态
function toggleStatus(data, status) {
if (data.children.length > 0) {
data.children.map(currentData => {
currentData.checked = status;
if (currentData.children.length > 0) {
toggleStatus(currentData, status);
}
})
}
};
// 获取选中数据,切换选中状态
function toogleChecked(data, val, isInit) {
data.map(currentData => {
if (currentData.id == val) {
currentData.checked = !currentData.checked;
if (currentData.checked) {
arrId.push(currentData.name);
toggleStatus(currentData, true);
} else {
let index = arrId.indexOf(currentData.name);
arrId.splice(index, 1);
toggleStatus(currentData, false);
}
} else if (currentData.children.length > 0) {
toogleChecked(currentData.children, val, "NoInit");
}
})
};
// 获取选中数据,切换选中状态,刷新数据
function selectionFunc(id,checked) {
toogleChecked(data, id);
container.innerHTML = getParent(data);
let EleColor = document.getElementById(id).classList;
if (!checked) {
EleColor.add("focusClass");
} else {
EleColor.remove("focusClass");
}
}
// 确认数据,规范化参数,
function ascertainVaL(data, val, inpuId) {
console.log("val", val, "inpuId", inpuId)
data.map((currentData) => {
if (currentData.id == val) {
currentData.edit = false;
if (inpuId.textContent == "") {
inpuId.textContent = "默认值"
}
currentData.name = inpuId.textContent;
} else if (currentData.children.length > 0) {
ascertainVaL(currentData.children, val, inpuId);
}
})
};
// 确定数据,刷新页面
function ascertain(val) {
let inpuId = document.getElementById(val);
console.log("val", val);
ascertainVaL(data, val, inpuId);
container.innerHTML = getParent(data);
};
//生成默认数据,把数据加入源数据
function addVal(data, val, randomId) {
data.map((currentData) => {
if (currentData.id == val) {
let temObj = {
id: randomId,
name: "默认值",
edit: true,
children: []
};
currentData.children.push(temObj);
} else if (currentData.children.length > 0) {
addVal(currentData.children, val, randomId);
}
})
console.warn("randomId", randomId)
return randomId;
};
// 新建数据,把数据加入源数据,刷新页面
function add(val) {
let randomId = val + Math.ceil(Math.random(9999) * 10000) + 1000;
let targetId = addVal(data, val, randomId);
container.innerHTML = getParent(data);
document.getElementById(targetId).focus();
}
// 删除数据
function remove(val) {
let removeVal = function (data) {
data.map(currentData => {
if (currentData.id == val) {
currentData.id = 9999;
} else if (currentData.children.length > 0) {
removeVal(currentData.children);
}
})
}
removeVal(data);
container.innerHTML = getParent(data);
}
// 获取父级数据
function getParent(currentData) {
if (currentData.id == "") return;
let html = "";
currentData.map(data => {
let htmlValue = "";
if (data.id != 9999) {
htmlValue = `
<div class= "containerParent">
<div class="parentChild">
<img src = ${data.spread == true ? "./imgs/free.svg" : "./imgs/shrink.svg"} alt="切换是否显示图标" class="Icon_class" onclick = ${`"toggleFnc(${data.id})"`} />
<span data-appid=${data.id} class="parent_span">${data.name}</span>
<img src = "./imgs/add.svg" alt="新增按钮" class="Icon_class parentIcon" onclick = ${`"add(${data.id})"`} />
</div>
${data.children && data.children.length > 0 ? getChildren(data.children) : ""}
</div>
`
}
html += htmlValue;
})
return html;
}
// 获取子树数据
function getChildren(data) {
let currentData;
let html = "";
if (data.id == "" || data.id == 9999) return html;
data.map((cuttentDate) => {
if (cuttentDate.id == 9999) return html;
let htmlValue
if (cuttentDate.id) {
let spanVal = `<img src = "./imgs/define.svg" alt="确定按钮" class="Icon_class" onclick = ascertain(${cuttentDate.id})>`;
let inputClick = cuttentDate.id + "checkbox"
htmlValue =
`
<div class="containerChildren">
<span class="descriter">...</span>
${cuttentDate.checked == true ?
`<img src = "./imgs/checked.svg" onclick = ${`"selectionFunc(${cuttentDate.id},${cuttentDate.checked})"`} id=${inputClick} alt="选中按钮" class="Icon_class" >` :
`<img src = "./imgs/unChecked.svg" onclick = ${`"selectionFunc(${cuttentDate.id},${cuttentDate.checked})"`} id=${inputClick} alt="不选中按钮" class="Icon_class">`
}
<span id=${cuttentDate.id} contenteditable = ${cuttentDate["edit"]} class="editContainer" title=${cuttentDate.name}>${cuttentDate.name}</span>
${cuttentDate.edit == false ? "" : spanVal}
<img src = "./imgs/add.svg" alt="新增按钮" class="Icon_class" onclick = ${`"add(${cuttentDate.id})"`}>
<img src = "./imgs/remove.svg" alt="删除按钮" class="Icon_class" onclick = ${`"remove(${cuttentDate.id})"`}>
${cuttentDate.children && cuttentDate.children.length > 0 ? getChildren(cuttentDate.children) : ""}
</div >
`
}
html += htmlValue
})
return html
}
//双击触发事件
function dbClickFnc(e) {
let targetValue = (e.targetValue || e.srcElement).id;
if (targetValue) {
let getData = function (data) {
data.map(currentData => {
if (currentData.id == targetValue) {
if (e.type == 'focusout') {
currentData.edit = false;
} else {
currentData.edit = true;
}
} else if (currentData.children.length > 0) {
getData(currentData.children);
}
}
)
}
getData(data);
container.innerHTML = getParent(data);
let getEle = document.getElementById(targetValue);
getEle.focus();
}
}
const container = document.getElementById("container");
container.addEventListener("dblclick", dbClickFnc, false)
container.innerHTML = getParent(data);
</script>
</html>

浙公网安备 33010602011771号