项目需求:一个产品树,当点击一个节点的时候获取当前节点以及所有父级节点的id,并调用兄弟组件(form组件)的方法进行查询操作,查询的结果需要渲染在table组件中。
1.首先明确这个页面的组件结构,是由 Tree、Form、Table组件组成。
// index.js 父组件
<Card bordered={false} title="商品SPU列表" className={style.antCardBox}>
<div className={style.antTreeBox}>
<OrderTree/>
</div>
<div style={{ flex: '1' }}>
<OrderForm />
<OrderTable />
</div>
</Card>
来看下页面渲染结果,使用flex布局,左边Tree组件宽度固定,右边自适应剩余空间。同时Tree中节点文字过长会省略号...展示,并且鼠标悬浮提示全部内容。
css样式:
.antCardBox {
:global {
.ant-card-body {
display: flex !important;
}
}
}
.antTreeBox {
width: 250px;
margin-right: 30px;
box-shadow: 3px -3px 6px 0px #ccc6;
:global {
.ant-tree li .ant-tree-node-content-wrapper.ant-tree-node-selected {
background-color: #50d38c !important;
color: white;
}
.ant-tree.ant-tree-icon-hide {
max-height: 900px !important;
overflow: auto !important;
}
.ant-tree-title {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: inline-block;
width: 170px;
}
.ant-spin.ant-spin-spinning {
margin-top: 30%;
}
}
}
2.明确要解决的问题有以下2个:
- 如何在点击树节点的时候获取当前节点以及所有父级节点的id?
- Tree组件获取到id后如何执行Form组件中的查询方法?
如何在点击树节点的时候获取当前节点以及所有父级节点的id?
解决方法:就是对从后台获取的数据进行递归遍历获取所需要的key和value。
let keysObj = {}; // 当前节点以及所有父节点的id
const intetorFun = (data, key, string) => {
if (string) {
firstParentKey = {
[data.param]: data.paramId,
};
}
if (data.children && data.children.length !== 0) {
data.children.forEach(item => {
if (item.id === key[0]) {
keysObj = {
[data.param]: data.paramId,
[item.param]: item.paramId,
...firstParentKey,
};
} else {
intetorFun(item, key);
}
});
}
return keysObj;
};
const getParentKey = (key, treeData) => {
let parentKey = [];
for (let i = 0; i < treeData.length; i++) {
const node = treeData[i];
// ‘firstTime’是设置的一个标记,根据这个标记把一级父节点的id记录在firstParentKey中
parentKey = intetorFun(node, key, 'firstTime');
}
return parentKey;
};
Tree组件获取到id后如何执行Form组件中的查询方法?
调用Form组件的查询方法需要在他们的父组件中进行操作,要在父组件中获取Tree和Form组件的实例,通过实例调用方法。
// index.js 父组件
onRef = ref => {
this.orderForm = ref; //获取Form组件的实例
};
treeRef = ref => {
this.orderTree = ref; //获取Tree组件的实例
};
getIdObject = data => {
this.setState({idObject: data},() => {
// 在Form组件中根据点击的树节点id,回填类型下拉选择框
this.orderForm.props.form.setFieldsValue({
categoryIds: [String(data.categoryId)],
});
// 调用Form组件的查询方法
this.orderForm.inquery(data);
});
};
<Card bordered={false} title="商品SPU列表" className={style.antCardBox}>
<div className={style.antTreeBox}>
<OrderTree idObject={this.getIdObject} treeRef={this.treeRef} />
</div>
<div style={{ flex: '1' }}>
<OrderForm onRef={this.onRef} isReact={this.isReact} />
<OrderTable />
</div>
</Card>
// 在Tree和Form组件中在componentDidMount生命周期中把自己传给父组件
// Tree组件中
componentDidMount() {
this.props.treeRef && this.props.treeRef(this);
}
// 在点击树节点的时候
//点击树节点时触发
onSelect = (selectKeys, e) => {
const { dispatch } = this.props;
const {
commodity: { treeData },
} = this.props;
this.setState({
selectedKeys: selectKeys,
});
let arrKeys = {};
//只有节点选中了才执行代码
if (e.selected && e.node.props.dataRef.param !== 'categoryId') {
keysObj = {};
firstParentKey = {};
arrKeys = getParentKey(selectKeys, treeData);
} else if (e.selected && e.node.props.dataRef.param === 'categoryId') { //点击的是一级根节点
keysObj = {};
firstParentKey = {};
arrKeys = {
categoryId: e.node.props.dataRef.paramId,
};
} else if (!e.selected) {
this.setState({
selectedKeys: [],
});
return false;
}
this.props.idObject(arrKeys); // 将获取到的所有父级id传给父组件
};
// Form组件中
componentDidMount() {
this.props.onRef && this.props.onRef(this);
}