你看下面这个react文件,它展现了一棵树状结构,并且可以展开合并节点,如果我想在节点展开和合并时有渐变效果,你可以帮我实现吗?
你看下面这个react文件,它展现了一棵树状结构,并且可以展开合并节点,如果我想在节点展开和合并时有渐变效果,你可以帮我实现吗?
/**
* @file
* @author
* @version
* @since
* @description This is a generic component used to show the cube's outline (dimensions roles tree).
*/
import * as React from 'react';
import Box from '@mui/material/Box';
import { useEffect, useState } from 'react';
import MetaApi from '../utils/meta-api';
const CubeOutline = ({ cubeGid, callback_selected_node }) => {
const [tree, setTree] = useState([]);
const [selectedNode, setSelectedNode] = useState(null); // 新增选中节点的状态
useEffect(() => {
const data_initialization = async () => {
// 根据cube_gid查询meta-api,获得包括度量在内的全部维度角色。
if (cubeGid) {
const dim_roles = await MetaApi.load_cube_dim_roles(cubeGid);
const mapping = dim_roles.map((dr) => ({
key: `${dr.gid}`,
state: '[ + ]',
display: `[维度角色] ${dr.name}`,
type: 'dimension_role',
olapEntity: dr,
children: [],
}));
setTree(mapping);
}
};
data_initialization();
}, [cubeGid]); // 依赖数组中包含cubeGid,确保每次cubeGid变化时都重新发起请求
// 切换节点展开/闭合状态的函数
const toggleNodeState = async (node) => {
node.state = node.state === '[ + ]' ? '[ - ]' : '[ + ]'; // 切换状态
if (node.state === '[ - ]') {
if (node.type === 'dimension_role') {
const dim_role = node.olapEntity;
const hierarchies = await MetaApi.load_dim_hierarchies(node.olapEntity.dimensionGid);
node.children = hierarchies.map((hierarchy) => ({
key: `${dim_role.gid}_${hierarchy.gid}`,
state: '[ + ]',
display: `[结构角色] ${hierarchy.name}`,
type: 'hierarchy_role',
olapEntity: {
dimensionRole: dim_role,
hierarchy,
},
children: [],
}));
} else if (node.type === 'hierarchy_role') {
const dimensionRole = node.olapEntity.dimensionRole;
const hierarchy = node.olapEntity.hierarchy;
const members = await MetaApi.load_hierarchy_members(hierarchy.gid);
const root = members.filter((m) => m.parentGid === 0)[0];
node.children = [{
key: `${dimensionRole.gid}_${root.gid}`,
state: '[ + ]',
display: `[成员角色] ${root.name}`,
type: 'member_role',
olapEntity: {
dimensionRole,
member: root,
},
children: [],
}];
} else if (node.type === 'member_role') {
const parent_member = node.olapEntity.member;
const hierarchy_gid = node.olapEntity.member.hierarchyGid;
let members = await MetaApi.load_hierarchy_members(hierarchy_gid);
members = members.filter((m) => m.parentGid === parent_member.gid);
node.children = members.map((m) => ({
key: `${node.olapEntity.dimensionRole.gid}_${m.gid}`,
state: '[ + ]',
display: `[成员角色] ${m.name}`,
type: 'member_role',
olapEntity: {
dimensionRole: node.olapEntity.dimensionRole,
member: m,
},
children: [],
}));
}
} else { // node.state === '[ + ]'
node.children = [];
}
setTree([...tree]); // 更新state以触发重新渲染
};
// 递归渲染树形结构的函数
const handleNodeClick = (node) => {
setSelectedNode(node.key); // 更新选中节点的key
callback_selected_node(node);
};
const renderTree = (node) => {
const isSelected = node.key === selectedNode; // 判断当前节点是否被选中
return (
<Box key={node.key} sx={{ paddingLeft: 2 }}>
<Box sx={{ textAlign: 'left' }}>
<Box>
{/* 点击切换节点展开/闭合状态 */}
<span
style={{ cursor: 'pointer' }}
onClick={() => toggleNodeState(node)} // 切换节点状态
>
{node.state}
</span>
{/* 点击时调用callback_selected_node,并传递当前的olapEntity */}
<span
style={{
cursor: 'pointer',
marginLeft: 8,
backgroundColor: isSelected ? '#d3d3d3' : 'transparent', // 设置选中节点的背景色
padding: '2px 4px', // 增加一些内边距,使背景色更明显
}}
onClick={() => handleNodeClick(node)} // 点击节点时更新选中状态
>
{node.display}
</span>
</Box>
</Box>
{/* 如果有子节点,递归渲染 */}
{node.children && node.children.length > 0 && (
<Box sx={{ paddingLeft: 2 }}>
{node.children.map(renderTree)}
</Box>
)}
</Box>
);
};
return (
<Box sx={{ minHeight: 352, minWidth: 250 }}>
{tree.map(renderTree)}
</Box>
);
};
export default CubeOutline;
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
为了在节点展开和合并时添加渐变效果,你可以使用 CSS 动画或者 react-spring
等动画库来实现平滑的展开和收起效果。这里我将给出一种使用 CSS 动画的实现方式。
修改步骤:
- 添加渐变效果:使用
transition
属性来实现节点展开和合并时的渐变效果。 - 动态控制高度:为节点的子节点容器设置一个可变的高度,并通过过渡效果来平滑地展开和收起。
- 动画过渡:通过设置
max-height
属性,并配合overflow
来控制节点展开和合并时的动画。
实现代码
我们会修改 toggleNodeState
方法,在切换节点状态时添加动画效果,并为树的每个节点容器设置过渡动画。
import * as React from 'react';
import Box from '@mui/material/Box';
import { useEffect, useState } from 'react';
import MetaApi from '../utils/meta-api';
const CubeOutline = ({ cubeGid, callback_selected_node }) => {
const [tree, setTree] = useState([]);
const [selectedNode, setSelectedNode] = useState(null); // 新增选中节点的状态
useEffect(() => {
const data_initialization = async () => {
if (cubeGid) {
const dim_roles = await MetaApi.load_cube_dim_roles(cubeGid);
const mapping = dim_roles.map((dr) => ({
key: `${dr.gid}`,
state: '[ + ]',
display: `[维度角色] ${dr.name}`,
type: 'dimension_role',
olapEntity: dr,
children: [],
}));
setTree(mapping);
}
};
data_initialization();
}, [cubeGid]);
// 切换节点展开/闭合状态的函数
const toggleNodeState = async (node) => {
node.state = node.state === '[ + ]' ? '[ - ]' : '[ + ]'; // 切换状态
if (node.state === '[ - ]') {
if (node.type === 'dimension_role') {
const dim_role = node.olapEntity;
const hierarchies = await MetaApi.load_dim_hierarchies(node.olapEntity.dimensionGid);
node.children = hierarchies.map((hierarchy) => ({
key: `${dim_role.gid}_${hierarchy.gid}`,
state: '[ + ]',
display: `[结构角色] ${hierarchy.name}`,
type: 'hierarchy_role',
olapEntity: {
dimensionRole: dim_role,
hierarchy,
},
children: [],
}));
} else if (node.type === 'hierarchy_role') {
const dimensionRole = node.olapEntity.dimensionRole;
const hierarchy = node.olapEntity.hierarchy;
const members = await MetaApi.load_hierarchy_members(hierarchy.gid);
const root = members.filter((m) => m.parentGid === 0)[0];
node.children = [{
key: `${dimensionRole.gid}_${root.gid}`,
state: '[ + ]',
display: `[成员角色] ${root.name}`,
type: 'member_role',
olapEntity: {
dimensionRole,
member: root,
},
children: [],
}];
} else if (node.type === 'member_role') {
const parent_member = node.olapEntity.member;
const hierarchy_gid = node.olapEntity.member.hierarchyGid;
let members = await MetaApi.load_hierarchy_members(hierarchy_gid);
members = members.filter((m) => m.parentGid === parent_member.gid);
node.children = members.map((m) => ({
key: `${node.olapEntity.dimensionRole.gid}_${m.gid}`,
state: '[ + ]',
display: `[成员角色] ${m.name}`,
type: 'member_role',
olapEntity: {
dimensionRole: node.olapEntity.dimensionRole,
member: m,
},
children: [],
}));
}
} else { // node.state === '[ + ]'
node.children = [];
}
setTree([...tree]); // 更新state以触发重新渲染
};
const handleNodeClick = (node) => {
setSelectedNode(node.key); // 更新选中节点的key
callback_selected_node(node);
};
// 渲染每个节点的树状结构
const renderTree = (node) => {
const isSelected = node.key === selectedNode; // 判断当前节点是否被选中
return (
<Box key={node.key} sx={{ paddingLeft: 2 }}>
<Box sx={{ textAlign: 'left' }}>
<Box>
{/* 点击切换节点展开/闭合状态 */}
<span
style={{ cursor: 'pointer' }}
onClick={() => toggleNodeState(node)} // 切换节点状态
>
{node.state}
</span>
{/* 点击时调用callback_selected_node,并传递当前的olapEntity */}
<span
style={{
cursor: 'pointer',
marginLeft: 8,
backgroundColor: isSelected ? '#d3d3d3' : 'transparent',
padding: '2px 4px', // 增加一些内边距,使背景色更明显
}}
onClick={() => handleNodeClick(node)} // 点击节点时更新选中状态
>
{node.display}
</span>
</Box>
</Box>
{/* 子节点的展开与折叠效果 */}
{node.children && node.children.length > 0 && (
<Box
sx={{
paddingLeft: 2,
overflow: 'hidden',
maxHeight: node.state === '[ - ]' ? '1000px' : '0px', // 控制最大高度
transition: 'max-height 0.3s ease-in-out', // 添加渐变效果
}}
>
{node.children.map(renderTree)}
</Box>
)}
</Box>
);
};
return (
<Box sx={{ minHeight: 352, minWidth: 250 }}>
{tree.map(renderTree)}
</Box>
);
};
export default CubeOutline;
关键修改:
-
添加渐变效果:
- 我在子节点容器 (
Box
) 上使用了max-height
属性,并将其设置为0px
或1000px
来控制节点展开和折叠的高度。 - 使用
transition: 'max-height 0.3s ease-in-out'
来实现渐变效果,这样节点展开或折叠时会有平滑过渡。
- 我在子节点容器 (
-
节点切换:每次点击展开或合并节点时,都会触发
toggleNodeState
方法,该方法会根据当前节点的状态来切换是否展开或折叠节点,并且重新渲染树状结构。 -
设置
max-height
:设置max-height
为1000px
使得展开时的子节点可见,并通过overflow: 'hidden'
隐藏折叠时的内容。你可以根据需要调整1000px
为合适的值。
结果:
- 点击每个节点时,展开和折叠都会有渐变效果,表现为平滑的展开和收缩。
- 点击节点时,选中的节点会变更背景颜色,体现出选中的状态。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
2021-02-25 K8S部署后测试nginx
2021-02-25 kube-flannel.yml
2021-02-25 centos7部署K8S