[TOC]
### 單次操作請求
~~~
import React, {Component} from 'react';
import { Tree, Spin, Tag ,message} from 'antd'
import * as consts from '../role/RoleConst'
import {connect} from 'dva'
const TreeNode = Tree.TreeNode;
let hashData = [];
class SelectSystem extends Component {
constructor(props) {
super(props);
const checkedKeys = [];
console.log('系統',props)
this.dealWithData(props.systemTree, checkedKeys);
this.state = {
checkedKeys: checkedKeys,
dataSource: props.systemTree
}
}
UNSAFE_componentWillReceiveProps(nextProps) {
const checkedKeys = [];
this.dealWithData(nextProps.systemTree, checkedKeys);
this.setState({
checkedKeys: checkedKeys,
dataSource: nextProps.systemTree
})
}
dealWithData (data, checkedKeys = [], parentKey = -1) {
if (data instanceof Array) {
data.map(item => {
item.name = item.name || item.containerName || item.toolName;
const key = item.code || item.containerCode || item.toolCode;
item.key = key;
item.parentKey = parentKey;
item.children = item.containers || item.subTools || [];
if (key && item.children.length <= 0 && item.isShare) checkedKeys.push(key);
this.dealWithData(item.children, checkedKeys, key)
})
}
}
renderTreeNodes(data) {
if (data instanceof Array) {
return data.map(item => {
const title = item.name;
const key = item.key;
hashData[key] = item;
return <TreeNode title={<div><span style={{marginRight: 5}}>{title}</span>{this.getTag(item)}</div>} key={key}>
{this.renderTreeNodes(item.children)}
</TreeNode>
})
}
return []
}
getTag(record) {
let title = null;
let color = "red";
if (record.code) {
title = "系統";
color = "geekblue";
} else if (record.containercode) {
title = "容器";
color = "blue";
} else if (record.isTool === 0) {
title = "工具組";
color = "cyan";
} else if (record.isTool === 1) {
title = "工具";
color = "green";
}
return title ? <Tag color={color}><span>{title}</span></Tag> : null;
}
onCheck (checkedKeys) {
const preCheckedKeys = [];
const currentCheckedKeys = [];
// console.log('this.props',this.props)
this.getKeys(this.state.checkedKeys, preCheckedKeys);
this.getKeys(checkedKeys, currentCheckedKeys);
let func = null;
const param = {
resourceCode: [],
targetDomain:''
};
if (preCheckedKeys.length > currentCheckedKeys.length) {
func = this.props.delSourceAuth
preCheckedKeys.map(item => {
if (currentCheckedKeys.indexOf(item) === -1) {
param.resourceCode.push(item);
param.targetDomain=this.props.code.domaincode;
}
})
} else {
func = this.props.addSourceAuth
currentCheckedKeys.map(item => {
if (preCheckedKeys.indexOf(item) === -1) {
param.resourceCode.push(item)
param.targetDomain=this.props.code.domaincode;
}
})
}
func && func(param).then(results=>{
this.setState({
checkedKeys
})
let res = results.code!==1000
if(!res){
this.setState({
curChecked:[],
curUnchecked:[]
});
// this.props.getShareSystem();
message.success("操作成功");
}else{
message.error("操作失敗");
}
}
);
}
findParent(key, desArr = []) {
const a = hashData[key];
if (!a) return;
if (desArr.indexOf(a.key) === -1) {
desArr.push(a.key);
if (a.parentKey && a.parentKey !== -1) {
this.findParent(a.parentKey, desArr)
}
}
}
getKeys(data = [], desArr = []) {
data.map(item => {
const a = hashData[item];
if (!a) return;
if (a.children.length <= 0 && desArr.indexOf(item) === -1) {
desArr.push(item);
if (a.parentKey && a.parentKey !== -1) {
this.findParent(a.parentKey, desArr);
}
}
})
}
render() {
hashData = [];
return (
<Spin spinning={this.props.loading}>
<div style={{minHeight: 250, overflowY: "auto", maxHeight: 450}}>
{
this.props.systemTree.length > 0 ? <Tree
checkable
defaultExpandAll
checkedKeys={this.state.checkedKeys}
onCheck={this.onCheck.bind(this)}
>
{this.renderTreeNodes(this.state.dataSource)}
</Tree> : <div style={{textAlign: "center", marginTop: 20}}>暫無數據</div>
}
</div>
</Spin>
)
}
}
function mapStateToProps(state){
return {
loading: state.loading.models.system,
...state.system
};
}
export default connect(mapStateToProps)(SelectSystem);
~~~
### 含保存按鈕的
~~~
import React, { Component } from 'react'
import { Tree, List, Icon, Button, Spin } from 'antd'
import style from '../role/role.css'
import {connect} from 'dva'
import { message } from 'antd';
const TreeNode = Tree.TreeNode;
//獲取接口中所有的子元素的code再和父元素的code進行拼接
因為tree中的key被樹的 (default)ExpandedKeys / (default)CheckedKeys / (default)SelectedKeys 屬性所用。注意:整個樹范圍內的所有節點的 key 值不能重復!,有可能后臺提供的接口中對應的key相同的話,項目就會報錯,所有用拼接的方法,將所有的節點的key和它的父節點的key進行拼接,來實現key的唯一性
const getDataContentDic = (data, dic) => {
data.map(item => {
if (item && item.code) {
const key = item.code + '^' +(item.parentcode? item.parentcode : '');
dic[key] = item;
if (item.sub instanceof Array) {
getDataContentDic(item.sub, dic);
}
}
});
};
let dataContentDic = [];
let topicKeys = [];
let lastChecked = [];
class SelectResourcesData extends Component {
constructor(props) {
super(props);
// console.log('llllllllllllllllllll',props)
let selectDataContent = null;
if (props.thematicScheme instanceof Array) {
if (props.thematicScheme.length > 0) {
selectDataContent = props.thematicScheme[0];
}
dataContentDic = [];
getDataContentDic([selectDataContent], dataContentDic);
}
const initState = this.initUI(selectDataContent);
this.state = {
selectDataContent,
checkedKeys: initState.checkedKeys,
checkStrictly: initState.checkStrictly,
expandedKeys: initState.expandedKeys,
curChecked: [],
curUnchecked: []
}
}
UNSAFE_componentWillReceiveProps(nextProps) {
let selectDataContent = null;
if (nextProps.thematicScheme instanceof Array) {
const findSDC = this.state.selectDataContent ? nextProps.thematicScheme.filter(it => (it.code === this.state.selectDataContent.code)) : [];
if (findSDC.length > 0) {
selectDataContent = findSDC[0]
} else if (nextProps.thematicScheme.length > 0) {
selectDataContent = nextProps.thematicScheme[0];
}
dataContentDic = [];
getDataContentDic([selectDataContent], dataContentDic);
const initState = this.initUI(selectDataContent);
this.setState({
selectDataContent,
checkedKeys: initState.checkedKeys,
checkStrictly: initState.checkStrictly,
expandedKeys: initState.expandedKeys,
curChecked: [],
curUnchecked: []
})
}
}
onDataContentListClick(record, isFirst) {
dataContentDic = [];
getDataContentDic([record], dataContentDic);
const initState = this.initUI(record);
if (!isFirst) {
this.setState({
selectDataContent: record,
checkedKeys: initState.checkedKeys,
checkStrictly: initState.checkStrictly,
expandedKeys: initState.expandedKeys,
curChecked: [],
curUnchecked: []
})
}
}
initUI(record) {
let checkedKeys = { checked: [], halfChecked: [] };
let checkStrictly = true;
const expandedKeys = this.findExpandedKeys(dataContentDic);
if (record) {
checkedKeys = this.findCheckedTopicKeys(dataContentDic);
checkStrictly = false;
}
topicKeys = this.getTopicKeys(dataContentDic);
lastChecked = checkedKeys;
return {
checkedKeys,
checkStrictly,
expandedKeys
}
}
findExpandedKeys(data) {
const keys = [];
for (let key in data) {
const item = dataContentDic[key];
if (Object.prototype.toString.apply(item) !== "[object Function]" && item.sub instanceof Array && item.sub.length > 0) {
keys.push(key);
}
}
return keys;
}
//獲取接口中保存的為選擇狀態的key
findCheckedTopicKeys(data) {
const keys = [];
for (let key in data) {
const item = dataContentDic[key];
if (Object.prototype.toString.apply(item) !== "[object Function]" && !item.type && item.topictype === 1 && item.isShare === true) {
keys.push(key);
}
}
return keys;
}
//獲取接口數據中所有key
getTopicKeys(data){
const keys = [];
for (let key in data) {
const item = dataContentDic[key];
if (Object.prototype.toString.apply(item) !== "[object Function]" && !item.type && item.topictype === 1 ) {
keys.push(key);
}
}
return keys;
}
//點擊復選框時觸發
onCheck(keys, {checked, node}) {
// console.log("keys",keys)//選中包含父節點的key
// console.log("checkedKeys",this.state)//選中的子節點的key
// var _lastKeys = lastKeys.map(item => item.split('^')[0]);
let tempKeys = keys instanceof Array ? keys : [...keys.checked];
tempKeys = tempKeys.filter(item => topicKeys.indexOf(item)>-1);//去除所有父節點
let checkedKeys = [...tempKeys];
let curKey = node.props.eventKey
let curCode = curKey.split('^')[0];
let spliceIndexs = [];
let childs = [];
//去除相同code的情況
if(node.props.children && node.props.children.length){//存在子節點
let temp = this.getSubKey(curKey);
temp = temp.filter(item =>topicKeys.indexOf(item)>-1);;
temp.map(item => {
if(checked){
checkedKeys = checkedKeys.concat(topicKeys.filter(key => key.split('^')[0]===item.split('^')[0]));
}else{
tempKeys.map((it, index)=> {
item.split('^')[0] === it.split('^')[0] && spliceIndexs.push(index);
})
}
})
// 通過上次已勾選的鍵得到凈鍵
childs = temp.filter(item => {
let exist = lastChecked.indexOf(item);
return checked ? exist===-1 : exist>-1;
});
}
else{//最下級節點
if(checked){
checkedKeys = checkedKeys.concat(topicKeys.filter(key => key.split('^')[0]===curCode));
}
else{
tempKeys.map((item,index) => {
item.split('^')[0] === curCode && spliceIndexs.push(index);
})
}
}
spliceIndexs = [...new Set(spliceIndexs.sort())].reverse();//排序,去重,反轉
spliceIndexs.map(item => {
checkedKeys.splice(item, 1);
});
// 增加刪除的內容
const {curChecked, curUnchecked} = this.getAddDelKeys(checked, curCode, childs);
lastChecked = checkedKeys;
this.setState({
checkedKeys,
checkStrictly: false,
curChecked,
curUnchecked
})
}
getAddDelKeys(checked, curCode, childs) {
let curChecked = [...this.state.curChecked];
let curUnchecked = [...this.state.curUnchecked];
childs = childs.length ? childs.map(item=>item.split('^')[0]) : [curCode];
if (checked) {
const {delArr, addArr} = this.updateAddDelKeys(childs, curUnchecked, curChecked);
curUnchecked = delArr;
curChecked = addArr;
} else {
const {delArr, addArr} = this.updateAddDelKeys(childs, curChecked, curUnchecked);
curChecked = delArr;
curUnchecked = addArr;
}
return {curChecked, curUnchecked};
}
/**
* 更新要刪除和要增加的鍵
* @param {*} codes
* @param {*} delArr
* @param {*} addArr
*/
updateAddDelKeys (codes, delArr, addArr) {
delArr = delArr.filter(
item => {
let exist = codes.indexOf(item);
if(exist === -1){
return true;
}
else{
codes.splice(exist, 1);
}
}
);
addArr = addArr.concat(codes);
return {delArr, addArr};
}
//獲取子節點的key
getSubKey(key) {
let des = [];
const item = dataContentDic[key];
if (item.sub instanceof Array) {
for (let i = 0; i < item.sub.length; i++) {
const key = item.sub[i].code+'^'+item.sub[i].parentcode;
des.push(key);
des = des.concat(this.getSubKey(key))
}
}
return des;
}
onSave() {
//樹主要操作的是子節點(先取出接口中的子節點code當成key然后再實現相應邏輯,父節點是否勾選通過checkStrictly屬性判斷是否關聯)
//實現邏輯:將現階段新添加和取消的數據(這部分數據可從onCheck函數中獲得)與原數據進行對比(tree中的checkedKeys勾選狀態的數據),將新添加的數據和取消的數據分別取出來。
// 子節點的key可能存在相同的情況,如果是相同的就去重
let proms = [];
let {curChecked, curUnchecked, selectDataContent} = this.state;
let readyDelList={};
let readyAddList={};
readyDelList.targetDomain=this.props.code.domaincode;
readyAddList.targetDomain=this.props.code.domaincode;
readyDelList.resourceCode=curUnchecked
readyAddList.resourceCode=curChecked
curUnchecked.length && proms.push(this.props.delSourceAuth(readyDelList))
curChecked.length && curChecked.unshift(selectDataContent.code) && proms.push(this.props.addSourceAuth(readyAddList))
proms.length && Promise.all(proms).then(results=>{
let res = results.some(result=>result.code!==1000)
if(!res){
this.setState({
curChecked:[],
curUnchecked:[]
});
// this.props.getShareSystem();
message.success("保存成功");
}else{
message.error("保存失敗");
}
})
}
getRightContent(data) {
if (data instanceof Array) {
return data.map(item => {
const key = item.code+'^'+(item.parentcode ? item.parentcode : '');
return <TreeNode title={(item.name ? item.name : item.topicname) || '未知'} key={key} selectable={false}>
{this.getRightContent(item.sub)}
</TreeNode>
})
}
return null
}
getRightTree(data){
const treeProps = {
//已選中的子節點的key(也就是接口中的唯一標識符code)
checkedKeys: this.state.checkedKeys,
//判斷是否關聯,當點擊子節點復選框時,父節點是否一起勾選
checkStrictly: this.state.checkStrictly,
checkable: true,
// defaultExpandAll: true,
// autoExpandParent: true,
//點擊復選框時觸發
onCheck: this.onCheck.bind(this),
//展開指定的樹節點
expandedKeys: this.state.expandedKeys,
//展開/收起節點時觸發(一般與上連用)
onExpand: this.onExpand.bind(this),
}
return data.length ? (<Tree
{...treeProps}
>
{this.getRightContent(data)}
</Tree>) : null;
}
getLeftList(data) {
if (data instanceof Array && data.length <= 0) {
return
}
if (!this.state.selectDataContent) {
this.onDataContentListClick(data[0], true);
}
return <List itemLayout="horizontal"
dataSource={data || []}
renderItem={(item, index) => (
<List.Item
onClick={this.onDataContentListClick.bind(this, item, false)}
actions={[<Icon type='right' style={{ fontSize: 19, color: `${this.state.selectDataContent === item ? "white" : "rgba(0, 0, 0, 0.65)"}` }} />]}
className={this.state.selectDataContent === item ? style.active : null}>
<div style={{ paddingLeft: 5, marginRight: -45 }}>{item.name}</div>
</List.Item>
)} />
}
getSubCatalog(key) {
let res = [];
let temp = dataContentDic[key];
if (temp.sub) {
temp.sub.map(item => {
if (item.sub) {
const key = item.code + '^' + item.parentcode;
res.push(key);
res = res.concat(this.getSubCatalog(key))
}
});
}
return res;
}
//收起,展開數結構
onExpand(keys, {expanded, node}) {
const key = node.props.eventKey;
let expandedKeys = [...keys];
let temp = this.getSubCatalog(key);
if(!expanded){
expandedKeys = expandedKeys.filter(item => {
return temp.indexOf(item)===-1;
});
}
else{
expandedKeys = expandedKeys.concat(temp);
}
this.setState({
expandedKeys
})
}
render() {
return (
<Spin spinning={this.props.loading}>
<div className={style.dataContentPaneContent}>
<div className={style.dataContentLeftContent}>
<div className={style.header}>數據資源目錄列表</div>
<div className={style.content}>
{this.getLeftList(this.props.thematicScheme)}
</div>
</div>
<div className={style.dataContentCenterContent}>
>
</div>
<div className={style.dataContentRightContent}>
<div className={style.header}>
<span>數據資源目錄樹</span>
<Button className={style["ant-btn"]} onClick={this.onSave.bind(this)} disabled={!this.state.selectDataContent} size="small">保存</Button>
</div>
<div className={style.content}>
{this.getRightTree(this.state.selectDataContent ? [this.state.selectDataContent] : [])}
</div>
</div>
</div>
</Spin>
)
}
}
function mapStateToProps(state){
return {
loading: state.loading.models.system,
...state.system
};
}
export default connect(mapStateToProps)(SelectResourcesData);
~~~
- 第一章 起步
- 第1節 創建react項目
- 第2節 hello world
- 第3節 數據綁定+事件處理
- 3.1 for循環事件處理中的傳參寫法、條件渲染
- 第4章 點擊切換文字
- 第5章 使用html寫react
- 第二章 運用
- 第1節 循環
- 第2節 實現一個簡單的TodoList
- 第2.1節 刪除
- 第3節 父子組件傳參
- 1. 父組件向子組件傳參
- 2. 子組件向父組件傳參
- 第4節 react-router實現一個簡單路由
- 第5節 生命周期
- 第6節 取數據
- 第 7節 獲取dom節點
- 第8節 雙向數據綁定
- 第三章 redux
- 第1節 介紹
- 第2節 安裝redux
- 第3節 使用
- 3.1 action
- 3.2 使用redux實現 todolist
- 第4節封裝redux中的action
- 第5節 redux-thunk中間件
- 5.1介紹
- 5.2使用
- 第四章 ant-design前端ui
- 第一節 安裝
- 第2節 使用
- 2.1 ant-design實現todoList增刪功能
- 第3節 使用整理
- 第五章 vue和react的比較
- 第六章 dva.js輕量級應用框架
- 第1節 介紹
- 第2節 安裝dva
- 第3節 頁面跳轉
- 1. 事件路由跳轉
- 2. 通過路由跳轉
- 第4節 組件之間通信
- 1. 父組件向子組件傳參
- 2. 子組件向父組件傳參
- 第5節 事件處理
- 第6節 發送請求
- 1. 通過路由判斷頁面渲染數據
- 2. 通過事件發送請求
- 第7節 運用
- 1. TodoList
- 1.添加數據
- 1.2輸入框敲回車觸發事件
- 2.刪除數據
- 3. 總結
- 第8節 配合antd使用
- 1. 引入antd
- 2.dva 使用antd注意事項
- 3. 知識點整理
- 第七章 dva后臺項目實戰
- 第1節 登錄加密
- 1.具體實現
- 第2節 知識點
- 第3節 樹結構
- 第八章 react新特性 hooks
- 第1節 hooks介紹
- 第2節 useState的使用
- 第3節 useEffect的使用
- 第4節 dva+antd+hooks企業后臺項目開發流程
- 第 5節 hooks 使用
- 運用
- 第6節 hook整理
- 第7節 react memo
- 第九章 react中使用Echarts
- 知識點
- react中使用mobx
- 知識點
- react中使用rem
- 遞歸實現目錄數
- react使用圖表
- react 同步更新策略
- antd tree默認展開無效
- ts中lint修復篇
- React-query方案
- 高階組件