前端後端配合對樹型結構進行優化

項目開發的過程中經常會遇到樹狀的數據,比如:選城市,選分類,選公司部門等等等等。。。基本上都是保存的樹狀結構。

下面的圖就是一個典型的樹型結構,

  • id,唯一值
  • name,名字
  • isLeaf,是否是最末級的葉子節點
  • idPath,當前節點與所有父級節點的id以“,”拼接
  • parentId, 父節點id(如果沒有父節點則此字段返回值爲null)
  • children,孩子節點(如果沒有孩子節點則此字段返回值爲null)

關聯關係就是如果isLeaf爲true那就沒有children,如果爲false那就有children。
在這裏插入圖片描述

如果你項目的樹結構的深度不是很深、數據不是很多,完全可以忽略本博客。

但是筆者的項目這個分類有七層左右的深度,一共五千多條數據,所以就必須進行優化了,否則每次都要加載八秒左右纔會生成這個TreeSelect。

接下來開始進行優化,我們先優化sql:

SELECT 
	id as key, 
	name as title, 
	isLeaf,
	parentId,
FROM AssetClassification
WHERE parentId = 前端傳過來的parentId;

初始化的第一層數據sql請後端朋友自行寫吧,我就不在寫了。

之前sql是把所有層級的分類都獲取了,而我們這次只獲取你點擊節點的子節點。

如果後端朋友還有什麼疑惑請在下方評論,筆者會十二小時之內解答。節日除外哈,週六週日正常解答。

接下來開始前端優化

筆者這邊是React項目,用的antd。

做此功能用了Tree組件。

接下來是代碼,註釋和說明我都寫在了代碼裏,

前端朋友們對於不懂的地方也請在下方留言哈!

import React, {Component} from 'react';
import {
  Input,
  Popover,
  Select,
  Tree,
  Tooltip,
} from 'antd';
import {
  getThePrimaryClassificationList,	// 請求初始化最上級分類的方法
  getAssetClassificationChildrenList,	// 請求當前節點子節點的方法
  getIsLeafClassificationData,	// 獲取當前選中節點的所有葉子級節點的方法(如果你不需要此功能就忽視)
} from '../../services/asset/getClassification';

const { Option } = Select;
const { Search } = Input;
const { TreeNode } = Tree;

export default class Index extends Component {
  constructor(props) {
    super(props);
    this.state = {
      assetClassificationList: [],	// 初始最上級的數據
      expandedKeys: [],
      autoExpandParent: true,
      checkedKeys: [], // 選中的key
      treeData: [],	// 分類的所有數據
      thePrimaryClassificationId: '',
      quertClassificationStr: '',
    };
  }

  componentDidMount() {
    this.getThePrimaryClassificationData();
    this.getAssetClassificationChildrenData();
  }

  onExpand = (expandedKeys) => {
    // console.log('onExpand', expandedKeys);
    // if not set autoExpandParent to false, if children expanded, parent can not collapse.
    // or, you can remove all expanded children keys.
    this.setState({
      expandedKeys,
      autoExpandParent: false,
    });
  };

  onCheck = async (checkedKeys) => {
    this.setState({
      checkedKeys,
    })
    let childKeys = [];
    if (checkedKeys.length > 0) {
      childKeys = await getIsLeafClassificationData(checkedKeys);
    }

    // 在這裏去觸發父組件,每次把結果返回給父組件
    this.props.onChangeValue(childKeys)
    // 這個是父組件要顯示的漢字
    const quertClassificationStr = childKeys.map(item => item.title).join(',');
    this.setState({
      quertClassificationStr,
    });
  };

  onSelect = (selectedKeys) => {
    this.onExpand(selectedKeys);
  };

  onLoadData = (treeNode = {}) => {
    return new Promise((resolve) => {
      if (treeNode.props.children) {
        resolve();
        return;
      }
      setTimeout(async () => {
        const childrenNodes = await getAssetClassificationChildrenList(treeNode.props.dataRef.key)
        treeNode.props.dataRef.children = childrenNodes;
        this.setState({
          treeData: [...this.state.treeData],
        });
        resolve();
      }, 500);
    });
  }

  getThePrimaryClassificationData = async () => {
    const res = await getThePrimaryClassificationList();
    this.setState({
      assetClassificationList: res,
    });
  }

  // 得到初始化的第一層數據
  getAssetClassificationChildrenData = async () => {
    const { thePrimaryClassificationId } = this.state;
    const classificationChildrenList = await getAssetClassificationChildrenList(thePrimaryClassificationId);
    this.setState({
      treeData: classificationChildrenList,
    });
  }
  // 渲染樹節點
  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 key={item.key} {...item} dataRef={item}/>;
    }) || [];
  }

  render() {
    const { treeData } = this.state;
    const component = (
      <div>
        <Tree
          checkable
          loadData={this.onLoadData} // 每次加載數據的時候觸發,我們這次優化的關鍵!!!
          onExpand={this.onExpand} // 展開的組件的時候觸發
          expandedKeys={this.state.expandedKeys}
          autoExpandParent={this.state.autoExpandParent}
          onCheck={this.onCheck} // 選中的時候觸發
          checkedKeys={this.state.checkedKeys}
          onSelect={this.onSelect} // 點擊行文字的時候觸發()
          style={{
            height: '300px',
            overflow: 'auto',
          }}
        >
          {this.renderTreeNodes(treeData)}
        </Tree>
      </div>
    );
    return (
      <div>
        <Popover
          content={component}
          trigger="click"
          placement="bottom"
        >
          <div>
            點此顯示分類選擇框
          </div>
        </Popover>
      </div>
    );
  }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章