1、实现效果
- 折叠菜单的层级可以不相同、可以无限层级,具体根据读取的数据库数据为依据
- 菜单内容读取数据库获得
- 具体效果如下
- 折叠菜单是否可以继续召开取决于前面是否有可召开图标,如下图所示
2、实现原理
- 初始化加载页面并未获取全部层级的数据,只是第一层级
- 如果有子层级则呈现可展开图标,可进一步加载呈现下一层级菜单内容,否则没有
- 是否可继续加载呈现下一层级,原理同上
3、代码实现分步解析
(1)第一步:依赖组件
-
-
- 本效果的实现主要是依赖于antd组件库中的Tree组件
-
- 所以在项目中需要引入该组件,代码如下
import { Tree} from 'antd';
const TreeNode = Tree.TreeNode;
(2)第二步:在状态机中设置用于存放初始化加载以及子层级菜单的数据内容
// 状态机
constructor(props, context) {
super(props, context);
this.state = {
treeData: [], //存放初始化加载的菜单内容,即第一层级菜单内容
TreeNodeData: [], //存放获取的子菜单内容
}
}
(3)第三步:折叠菜单Tree控件的呈现
renderTreeNodes(data) {
return data.map((item) => {
if (item.children) {
return (
<TreeNode title={item.title} key={item.key} dataRef={item}>
{this.renderTreeNodes(item.children)}
</TreeNode>
);
}
return <TreeNode {...item} title={item.title} dataRef={item} />;
});
}
render() {
return (
<Layout>
<Layout style={{ padding: '10px 0', background: '#fff' }}>
<Sider width={300} style={{ background: '#fff', paddingLeft: '15px' }}>
<Tree loadData={this.onLoadData} defaultSelectedKeys='0' >
{this.renderTreeNodes(this.state.treeData)}
</Tree>
</Sider>
</Layout>
</Layout>
);
}
(4)第四步:初始化加载第一层级菜单内容
- 利用componentWillMount周期函数,在初始化加载页面时进行网络请求,获取第一层级菜单数据
componentWillMount() {
const subject_name = '数学';
const grade = '初中';
this.getKnowledgeStorageFirstLayer(grade, subject_name); //获取第一层级菜单内容
}
// 获取第一层层级关系
getKnowledgeStorageFirstLayer(grade, subject_name) {
let ajaxTimeOut=$.ajax({
url: "/api_v1.1/knowledge/getKnowledgeStorager",
type: "GET",
dataType: "json",
data: { "grade": grade, "subject": subject_name },
timeout:2000,
success: function (data) {
if (data.errorCode == 0) {
console.log('成功获取第一层层级关系');
console.log(data);
this.setState({ treeData: data.msg });//将第一层级数据赋值给状态机
}
else {
console.log('暂无数据');
}
}.bind(this),
error: function (xhr, status, err) {
}.bind(this),
complete: function (XMLHttpRequest, status) { //请求完成后最终执行参数
if (status == 'timeout') {//超时,status还有success,error等值的情况
ajaxTimeOut.abort(); //取消请求
this.time_out()
}
}
});
}
(5)第五步:单击可展开图标,进行网络请求获取下一层级菜单内容
onLoadData = (treeNode) => {
return new Promise((resolve) => {
if (treeNode.props.children) {
resolve();
return;
}
this.getKnowledgeStorageNextLayer(treeNode.props.knowid);
setTimeout(() => {
treeNode.props.dataRef.children = this.state.TreeNodeData;
this.setState({
treeData: [...this.state.treeData],
});
resolve();
}, 1000);
});
}
// 通过id获取下一层层级关系
getKnowledgeStorageNextLayer(knowid) {
return new Promise((resolve) => {
let ajaxTimeOut= $.ajax({
url: "/api_v1.1/knowledge/getKageNextLayer",
type: "GET",
dataType: "json",
data: { "knowid": knowid },
timeout:2000,
success: function (data) {
if (data.errorCode == 1) {
console.log('没有下一层结构');
}
else {
console.log('成功获取下一层极结构');
console.log(data);
this.setState({ TreeNodeData: data.msg }); //将下一层级菜单内容赋值给状态机
}
}.bind(this),
error: function (xhr, status, err) {
}.bind(this),
complete: function (XMLHttpRequest, status) { //请求完成后最终执行参数
if (status == 'timeout') {//超时,status还有success,error等值的情况
ajaxTimeOut.abort(); //取消请求
}
}
});
})
}
4、整体代码
import React, { Component } from 'react';
import $ from 'jquery';
import '../../../style_css/antd.css';
import { Layout, Tree, Row, Col } from 'antd';
const { Header, Content, Footer, Sider } = Layout;
const TreeNode = Tree.TreeNode;
class KnowledgeRepository_List_Slider extends Component {
// 状态机
constructor(props, context) {
super(props, context);
this.state = {
treeData: [], //存放初始化加载的菜单内容,即第一层级菜单内容
TreeNodeData: [], //存放获取的子菜单内容
}
}
// 通过id获取第一层层级关系
getKnowledgeStorageFirstLayer(grade, subject_name) {
let ajaxTimeOut=$.ajax({
url: "/api_v1.1/knowledge/getKnowledgeStorageFirstLayer",
type: "GET",
dataType: "json",
data: { "grade": grade, "subject": subject_name },
timeout:2000,
success: function (data) {
if (data.errorCode == 0) {
console.log('成功获取第一层层级关系');
console.log(data);
this.setState({ treeData: data.msg });//将第一层级数据赋值给状态机
}
else {
console.log('暂无数据');
}
}.bind(this),
error: function (xhr, status, err) {
}.bind(this),
complete: function (XMLHttpRequest, status) { //请求完成后最终执行参数
if (status == 'timeout') {//超时,status还有success,error等值的情况
ajaxTimeOut.abort(); //取消请求
console.log('网络不稳定');
}
}
});
}
// 通过id获取下一层层级关系
getKnowledgeStorageNextLayer(knowid) {
return new Promise((resolve) => {
let ajaxTimeOut= $.ajax({
url: "/api_v1.1/knowledge/getKnowledgeStorageNextLayer",
type: "GET",
dataType: "json",
data: { "knowid": knowid },
timeout:2000,
success: function (data) {
if (data.errorCode == 1) {
console.log('没有下一层结构');
}
else {
console.log('成功获取下一层极结构');
console.log(data);
this.setState({ TreeNodeData: data.msg }); //将下一层级菜单内容赋值给状态机
}
}.bind(this),
error: function (xhr, status, err) {
}.bind(this),
complete: function (XMLHttpRequest, status) { //请求完成后最终执行参数
if (status == 'timeout') {//超时,status还有success,error等值的情况
ajaxTimeOut.abort(); //取消请求
console.log('网络不稳定');
}
}
});
})
}
onLoadData = (treeNode) => {
return new Promise((resolve) => {
if (treeNode.props.children) {
resolve();
return;
}
this.getKnowledgeStorageNextLayer(treeNode.props.knowid);
setTimeout(() => {
treeNode.props.dataRef.children = this.state.TreeNodeData;
this.setState({
treeData: [...this.state.treeData],
});
resolve();
}, 1000);
});
}
renderTreeNodes(data) {
return data.map((item) => {
if (item.children) {
return (
<TreeNode title={item.title} key={item.key} dataRef={item}>
{this.renderTreeNodes(item.children)}
</TreeNode>
);
}
return <TreeNode {...item} title={item.title} dataRef={item} />;
});
}
componentWillMount() {
const subject_name = '数学';
const grade = '初中';
this.getKnowledgeStorageFirstLayer(grade, subject_name); //获取第一层级菜单内容
}
render() {
return (
<Layout>
<Layout style={{ padding: '10px 0', background: '#fff' }}>
<Sider width={300} style={{ background: '#fff', paddingLeft: '15px' }}>
<Tree loadData={this.onLoadData} defaultSelectedKeys='0' >
{this.renderTreeNodes(this.state.treeData)}
</Tree>
</Sider>
</Layout>
</Layout>
);
}
}
export default KnowledgeRepository_List_Slider;
5、特别说明
- 由于此效果的实现依赖的是Tree控件,有些字段名称必须使用该控件是别的名字,如获取网络数据时,菜单名字必须使用title字段,是否包含子层级使用isLeaf字段(true:无;false:有)
- 具体请参考网址:https://ant.design/components/tree-cn/