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/