1. 程式人生 > >React中通過tree元件實現不確定層級的摺疊選單效果

React中通過tree元件實現不確定層級的摺疊選單效果

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:有)