鸿蒙中使用tree
1.代码
分为两个文件:1:测试数据。2.代码文件
需要用的话自己改改数据
他是个CustomDialog
2.调用
dialogController: CustomDialogController | null = new CustomDialogController({builder: dialogTree({}),backgroundColor: Color.Transparent,alignment: DialogAlignment.Bottom,offset: { dx: 0, dy: -20 },gridCount: 4,cornerRadius: 10,})
3.组件代码
import { getFontSize } from "common";
import { arr } from "./ss";// 原始数据接口,保持不变
export interface TreeNode {id: string | number;parentId: string | number;label: string;deptCode?: string;selectable?: boolean;weight?: number;children?: TreeNode[];
}// UI渲染专用的节点接口,继承自 TreeNode 并添加 expanded 属性
export interface UINode extends TreeNode {expanded?: boolean;
}export interface VisibleNode {node: UINode; // 更改为使用 UINode 接口level: number;
}@CustomDialog
@Component
export struct dialogTree {@State changeFontSize: number = getFontSize();@State treeData: TreeNode[] = arr;// 使用 Set 来高效存储展开的节点 ID@State expandedNodeIds: Set<string | number> = new Set();@State refreshKey: number = 0; // 新增一个状态变量controller?: CustomDialogController;getVisibleNodes(): VisibleNode[] {const result: VisibleNode[] = [];const traverse = (nodes: TreeNode[], level: number) => {for (const node of nodes) {// 判断当前节点是否在展开ID列表中const isExpanded = this.expandedNodeIds.has(node.id);console.log(`Node ID: ${node.id}, isExpanded: ${isExpanded}`);// 推入一个包含 `expanded` 属性的新 UINode 对象const uiNode: UINode = {id: node.id,parentId: node.parentId,label: node.label,deptCode: node.deptCode,selectable: node.selectable,weight: node.weight,children: node.children,expanded: isExpanded // 单独赋值 expanded 属性};result.push({ node: uiNode, level });console.log(`uiNode's expanded value: ${uiNode.expanded}`);// 如果节点已展开且有子节点,则递归遍历其子节点if (isExpanded && node.children) {traverse(node.children, level + 1);}}};traverse(this.treeData, 0);return result;}toggleNode(nodeId: string | number) {if (this.expandedNodeIds.has(nodeId)) {this.expandedNodeIds.delete(nodeId);} else {this.expandedNodeIds.add(nodeId);}this.refreshKey++;}@BuilderrenderTree(node: UINode, level: number) { // 更改为接受 UINode 类型Row() {// 动态缩进Text(' '.repeat(level)).fontSize(12);// 根据节点是否有子节点来渲染不同的UIif (node.children && node.children.length > 0) {// 根据节点是否展开来显示不同的图片if (node.expanded) {Image($r('app.media.zkls')).width(20).height(20).margin({ right: 8 }).onClick(() => {this.toggleNode(node.id);});} else {Image($r('app.media.hzhs')).width(20).height(20).margin({ right: 8 }).onClick(() => {this.toggleNode(node.id);});}} else {// 如果没有子节点,用Blank保持对齐Blank().width(28).margin({ right: 8 });}// 节点名称Text(node.label).fontSize(16).fontColor(node.children ? '#333333' : '#666666').height(40).onClick(() => {if (node.children) {this.toggleNode(node.id);} else {console.log(`打开文件: ${node.label}`);}});}.width('100%').padding({ left: 16, right: 16 })}build() {RelativeContainer() {Column() {Row() {Text('部门选择').fontWeight(FontWeight.Bold).fontSize(this.changeFontSize - 1)Image($r('app.media.gbxx')).width(13).height(13).onClick(() => {this.controller?.close()})}.padding(15).width('100%').justifyContent(FlexAlign.SpaceBetween)Divider().color('#1A000000').strokeWidth(0.5).width('90%')List() {ForEach(this.getVisibleNodes(), (item: VisibleNode) => {ListItem() {this.renderTree(item.node, item.level);}}, (item: VisibleNode) => item.node.id.toString() + this.refreshKey);}.width('100%').margin({ top: 20 }).height('80%')Row() {Button('取消', { type: ButtonType.Normal, stateEffect: true }).borderRadius(8).fontColor('#FF666666').backgroundColor('#FFE6E6E6').width(60).height(30).onClick(() => {this.controller?.close()})Button('确定', { type: ButtonType.Normal, stateEffect: true }).borderRadius(8).backgroundColor(0x317aff).width(60).height(30).margin({ left: 15 }).onClick(() => {})}.position({ bottom: 15, right: 15 })}.width('100%').height('100%')}.height('100%').width('100%');}
}