js实现comboxtree

实现 ComboTree 的 JavaScript 方法
ComboTree 是一种结合下拉框(ComboBox)和树形结构(Tree)的交互组件,常用于层级数据的选择。以下是实现方法:
基础 HTML 结构
<div class="combotree-container">
<input type="text" class="combotree-input" placeholder="Select..." readonly>
<div class="combotree-dropdown">
<ul class="combotree-tree">
<!-- 动态生成树节点 -->
</ul>
</div>
</div>
CSS 样式
.combotree-container {
position: relative;
width: 200px;
}
.combotree-input {
width: 100%;
padding: 8px;
border: 1px solid #ddd;
}
.combotree-dropdown {
display: none;
position: absolute;
width: 100%;
max-height: 300px;
overflow-y: auto;
border: 1px solid #ddd;
background: white;
z-index: 1000;
}
.combotree-tree {
list-style: none;
padding: 0;
margin: 0;
}
.combotree-tree li {
padding: 5px 10px;
cursor: pointer;
}
.combotree-tree li:hover {
background-color: #f5f5f5;
}
.combotree-tree li.has-children::before {
content: "+";
margin-right: 5px;
}
.combotree-tree li.expanded::before {
content: "-";
}
.combotree-tree li .children {
display: none;
margin-left: 15px;
}
.combotree-tree li.expanded .children {
display: block;
}
JavaScript 实现
class ComboTree {
constructor(containerId, data) {
this.container = document.getElementById(containerId);
this.data = data;
this.init();
}
init() {
this.createInput();
this.createDropdown();
this.renderTree();
this.bindEvents();
}
createInput() {
this.input = document.createElement('input');
this.input.className = 'combotree-input';
this.input.setAttribute('placeholder', 'Select...');
this.input.setAttribute('readonly', 'true');
this.container.appendChild(this.input);
}
createDropdown() {
this.dropdown = document.createElement('div');
this.dropdown.className = 'combotree-dropdown';
this.tree = document.createElement('ul');
this.tree.className = 'combotree-tree';
this.dropdown.appendChild(this.tree);
this.container.appendChild(this.dropdown);
}
renderTree() {
this.tree.innerHTML = '';
this.buildTree(this.data, this.tree);
}
buildTree(nodes, parentElement) {
nodes.forEach(node => {
const li = document.createElement('li');
li.textContent = node.text;
li.setAttribute('data-value', node.value);
if (node.children && node.children.length > 0) {
li.classList.add('has-children');
const span = document.createElement('span');
span.className = 'children';
li.appendChild(span);
this.buildTree(node.children, span);
}
parentElement.appendChild(li);
});
}
bindEvents() {
this.input.addEventListener('click', () => {
this.dropdown.style.display = this.dropdown.style.display === 'block' ? 'none' : 'block';
});
this.tree.addEventListener('click', (e) => {
const li = e.target.closest('li');
if (!li) return;
if (li.classList.contains('has-children')) {
li.classList.toggle('expanded');
} else {
this.input.value = li.textContent;
this.dropdown.style.display = 'none';
// 触发自定义事件
this.container.dispatchEvent(new CustomEvent('change', {
detail: {
value: li.getAttribute('data-value'),
text: li.textContent
}
}));
}
});
document.addEventListener('click', (e) => {
if (!this.container.contains(e.target)) {
this.dropdown.style.display = 'none';
}
});
}
}
使用方法
// 示例数据
const treeData = [
{
text: 'Parent 1',
value: 'p1',
children: [
{ text: 'Child 1', value: 'c1' },
{ text: 'Child 2', value: 'c2' }
]
},
{
text: 'Parent 2',
value: 'p2',
children: [
{
text: 'Child 3',
value: 'c3',
children: [
{ text: 'Grandchild 1', value: 'gc1' }
]
}
]
}
];
// 初始化
const comboTree = new ComboTree('container', treeData);
// 监听选择变化
document.getElementById('container').addEventListener('change', (e) => {
console.log('Selected:', e.detail);
});
功能扩展建议
- 添加搜索功能,在输入框中输入时过滤树节点
- 支持多选模式,允许选择多个节点
- 增加异步加载子节点的功能
- 添加自定义图标支持,替换默认的+/-符号
- 实现选中节点的高亮显示
注意事项
- 确保CSS样式不会与其他组件冲突
- 移动端需要考虑触摸事件的支持
- 大量数据时考虑虚拟滚动优化性能
- 无障碍访问需要额外添加ARIA属性







