关于antd tree和父子组件之间的传值问题(react 总结)

项目需求:点击产品树节点时获取该节点的所有父节点,同时回填表格的搜索条件,完成搜索功能,搜索结果展示在下方的table中。

写了三个组件:

现在有个业务场景交互:在orderTree组件中点击树节点,获取当前节点以及所有的父节点的Id 放入一个对象arrKeys中,并在orderForm组件中使用(回填类型下拉选择框,objId对象作为查询接口的入参)

现在可以分部解决问题:

1.首先获取点击的树节点以及所有父节点的id ---arrKeys

2.在点击树节点获取当前节点以及所有父级节点之后,通过this.props.idObject(arrKeys)把 arrKeys传给父组件。

3.在tree组件和form组件中的componentDidMount生命周期中把整个组件传给父组件

4.form组件中的inquery方法:

现附上tree.js代码

import React, { Component } from 'react';
import { connect } from 'dva';
import { Divider, Modal, Table, message, Tag, Spin } from 'antd';
import router from 'umi/router';
import style from '../style.less';
import { Tree, Input } from 'antd';

const { confirm } = Modal;
const { TreeNode } = Tree;
const { Search } = Input;
let dataList = [];
let keysObj = {}; // 当前节点以及所有父节点的id
let firstParentKey = {}; // 一级根节点的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, tree) => {
  let parentKey = [];
  for (let i = 0; i < tree.length; i++) {
    const node = tree[i];
    parentKey = intetorFun(node, key, 'firstTime');
  }
  return parentKey;
};
//搜索用的
const getSearchKey = (key, tree) => {
  let parentKey;
  for (let i = 0; i < tree.length; i++) {
    const node = tree[i];
    if (node.children) {
      if (node.children.some(item => item.id === key)) {
        parentKey = node.id;
      } else if (getSearchKey(key, node.children)) {
        parentKey = getSearchKey(key, node.children);
      }
    } else {
      if (node.id === key) {
        parentKey = node.id;
      }
    }
  }
  return parentKey;
};

@connect(({ commodity, loading, menu }) => ({
  commodity,
  loading: loading.effects['commodity/getTree'],
  menu,
}))
class OrderTree extends Component {
  constructor(props) {
    super(props);
    this.state = {
      expandedKeys: [], //默认展开一级根节点 props.commodity.defaultParentIdList
      searchValue: '',
      autoExpandParent: true,
    };
  }
  componentDidMount() {
    const { dispatch } = this.props;
    this.props.treeRef && this.props.treeRef(this); //挂载时把整个tree组件传给父组件
    dispatch({
      type: 'commodity/getTree',
      callback: res => {
        this.generateList(res.data);
        const defaultParentIdList = res.data.map(item => item.id);
        this.setState({
          expandedKeys: defaultParentIdList,
        });
      },
    });
  }
  generateList = data => {
    const { dispatch } = this.props;
    for (let i = 0; i < data.length; i++) {
      const node = data[i];
      const { id, name } = node;
      dataList.push({ id, name });
      dispatch({
        type: 'commodity/save',
        payload: {
          dataList,
        },
      });
      if (node.children) {
        this.generateList(node.children);
      }
    }
  };

  //展开/收起节点时触发
  onExpand = expandedKeys => {
    this.setState({
      expandedKeys,
      autoExpandParent: true,
    });
  };
  //点击树节点时触发
  onSelect = (selectKeys, e) => {
    const { dispatch } = this.props;
    const {
      commodity: { treeData },
    } = this.props;
    let arrKeys = {};
    //只有节点选中了才执行代码 dataRef是自定义在TreeNode上添加的属性,可以获取当前节点的所有信息
    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) {
      return false;
    }
    this.props.idObject(arrKeys);
  };
  // 搜索功能
  onChange = e => {
    const { value } = e.target;
    const {
      commodity: { treeData, dataList, defaultParentIdList },
    } = this.props;
    let expandedKeys = [];
    if (value) {
      expandedKeys = dataList
        .map(item => {
          if (item.name.toLowerCase().indexOf(value.toLowerCase()) > -1) {
            //不区分大小写
            return getSearchKey(item.id, treeData);
          }
          return null;
        })
        .filter((item, i, self) => item && self.indexOf(item) === i);
      this.setState({
        expandedKeys,
        searchValue: value,
        autoExpandParent: true,
      });
    } else {
      this.setState({
        expandedKeys: defaultParentIdList,
        searchValue: '',
        autoExpandParent: true,
      });
    }
  };

  render() {
    const { searchValue, expandedKeys, autoExpandParent } = this.state;
    const {
      commodity: { treeData },
      loading,
    } = this.props;
    const loop = data =>
      data.map(item => {
        const index = item.name.toLowerCase().indexOf(searchValue.toLowerCase()); //忽略大小写
        const beforeStr = item.name.substr(0, index);
        const afterStr = item.name.substr(index + searchValue.length);
        const centerStr = item.name.substr(index, searchValue.length);
        const title =
          index > -1 ? (
            <span title={item.name}>
              {beforeStr}
              <span style={{ color: '#f50' }}>{centerStr}</span>
              {afterStr}
            </span>
          ) : (
            <span title={item.name}>{item.name}</span>
          );
        if (item.children) {
          return (
            <TreeNode key={item.id} title={title} dataRef={item}>
              {loop(item.children)}
            </TreeNode>
          );
        }
        return <TreeNode key={item.id} title={title} dataRef={item} />;
      });
    return (
      <Spin spinning={loading}>
        <div>
          <Search style={{ marginBottom: 8 }} placeholder="Search" onChange={this.onChange} />
          <Tree
            onExpand={this.onExpand}
            onSelect={this.onSelect}
            expandedKeys={expandedKeys}
            autoExpandParent={autoExpandParent}
          >
            {loop(treeData)}
          </Tree>
        </div>
      </Spin>
    );
  }
}

export default OrderTree;

父组件index.js代码:

import React, { Component } from 'react';
import { connect } from 'dva';
import { formatMessage, FormattedMessage } from 'umi/locale';
import { Card, Spin } from 'antd';
import PageHeaderWrapper from '@/components/PageHeaderWrapper';
import OrderForm from './components/form';
import OrderTable from './components/table';
import OrderTree from './components/tree';
import style from './style.less';
import { consoleTestResultHandler } from 'tslint/lib/test';

// let dataList = [];

@connect(({ commodity, loading, menu }) => ({
  commodity,
  loading: loading.effects['commodity/getTree'],
  menu,
}))
class OrderPage extends Component {
  constructor() {
    super();
    this.state = {
      idObject: {},
      reactFlag: false,
    };
  }
  componentDidMount() {
    const { dispatch } = this.props;
    dispatch({
      type: 'commodity/getGoodsCategory',
    });
  }
  onRef = ref => {
    this.orderForm = ref;
  };
  treeRef = ref => {
    this.orderTree = ref;
  };
  getIdObject = data => {
    this.setState(
      {
        idObject: data,
      },
      () => {
        this.orderForm.props.form.setFieldsValue({
          categoryIds: [String(data.categoryId)],
        });
        this.orderForm.inquery(data);
      }
    );
  };
  //判断是否点击重置按钮
  isReact = ref => {
    const {
      commodity: { defaultParentIdList },
    } = this.props;
    if (ref) {
      this.orderTree.setState({
        expandedKeys: defaultParentIdList,
      });
    }
  };

  render() {
    return (
      <PageHeaderWrapper logo>
        <Card bordered={false} title="商品SPU列表" className={style.antCardBox}>
          <div
            style={{ width: '350px', marginRight: '30px', boxShadow: '3px -3px 6px 0px #ccc6' }}
            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>
      </PageHeaderWrapper>
    );
  }
}

export default OrderPage;

以上就是关于antd tree 和父子组件之间的传值问题(react 总结)的详细内容,更多关于antd tree 父子组件传值的资料请关注我们其它相关文章!

(0)

相关推荐

  • Element树形控件整合带图标的下拉菜单(tree+dropdown+input)

    目录 需求说明: 实现步骤: 本文主要讲述:自定义树形控件<el-tree> 需求说明: Element UI 官网提供的树形控件包含基础的.可选择的.自定义节点内容的.带节点过滤的以及可拖拽节点的树形结构 如下: 我想要的效果是支持搜索效果的树,将鼠标悬浮后显示添加修改图标,点击图标后弹出对应页面:并且在每个文件夹前添加自定义图标. 实现效果: 实现步骤: 1.使用插槽(slot) <el-col :span="4" :xs="24"> &

  • el-tree文字显示不全的解决办法

    目录 方法一: 最简单的设置横向滚动条 方法二(新): 添加拖拽条改变外层容器宽度 方法二(老): 添加拖拽条改变外层容器宽度 方法三: 通过...表示 鼠标移上去显示全称 使用element ui的树组件el-tree时,经常出现如下问题: el-tree渲染时因为文字内容长度不一致,导致过长的文字无法显示完全. 经尝试发现如下三种解决方法,推荐方法三. 方法一: 最简单的设置横向滚动条 效果: 在当前树节点的span标签上设置样式 overflow: auto; // 或者 overflow

  • C# TreeNode案例详解

    目录 添加节点 删除 修改 方法1: 方法二: 添加节点 private void Form1_Load(object sender, EventArgs e) { treeView1.LabelEdit = true;//可编辑状态. //添加一个节点,这个结点是根节点. TreeNode node = new TreeNode(); node.Text = "hope"; treeView1.Nodes.Add(node); TreeNode node1 = new TreeNod

  • 解析ConcurrentHashMap: 红黑树的代理类(TreeBin)

    前一章是get.remove方法分析,喜欢的朋友点击查看.本篇为ConcurrentHashMap源码系列的最后一篇,来分析一下TreeBin 红黑树代理节点的源码: 1.TreeBin内部类分析 TreeBin是红黑树的代理,对红黑树不太了解的,可以参考: static final class TreeBin<K,V> extends Node<K,V> { // 红黑树根节点 TreeNode<K,V> root; // 链表的头节点 volatile TreeNo

  • 面试必问项之Set实现类:TreeSet

    目录 一.TreeSet 概述 二.TreeSet 结构 1.TreeSet 声明 2.TreeSet 类继承结构 3.红黑树 三.TreeSet 创建 1.构造器 2.通过 Comparator 实例创建 TreeSet 四.TreeSet 方法 五.NavigableSet接口介绍 六.TreeSet 与 比较器 1.自然排序 2.定制排序 七.案例 1.自定义类的自然排序 2.自定义类的定制排序 总结 一.TreeSet 概述 1.TreeSet是 SortedSet 接口的实现类, Tr

  • JDK集合源码之解析TreeMap(一)

    目录 简介 继承体系 存储结构 源码解析 属性 Entry内部类 构造方法 get(Object key)方法 特性再回顾 左旋 右旋 插入元素 插入再平衡 插入元素举例 总结 简介 TreeMap使用红黑树存储元素,可以保证元素按key值的大小进行遍历. 继承体系 TreeMap实现了Map.SortedMap.NavigableMap.Cloneable.Serializable等接口. SortedMap规定了元素可以按key的大小来遍历,它定义了一些返回部分map的方法. public

  • JDK集合源码之解析TreeMap(二)

    目录 删除元素 删除再平衡 删除元素举例 二叉树的遍历 TreeMap的遍历 总结 总结 删除元素 删除元素本身比较简单,就是采用二叉树的删除规则. 如果删除的位置有两个叶子节点,则从其右子树中取最小的元素放到删除的位置,然后把删除位置移到替代元素的位置,进入下一步. 如果删除的位置只有一个叶子节点(有可能是经过第一步转换后的删除位置),则把那个叶子节点作为替代元素,放到删除的位置,然后把这个叶子节点删除. 如果删除的位置没有叶子节点,则直接把这个删除位置的元素删除即可. 针对红黑树,如果删除位

  • C++实现KDTree 附完整代码

    目录 简介 举例 分割的作用 一维 二维 n维 关于kdtree的重要问题 一.树的建立 关键代码 简介   k-d树(k-dimensional),是一种分割k维数据空间的数据结构(对数据点在k维空间中划分的一种数据结构),主要应用于多维空间关键数据的搜索(如:范围搜索和最近邻搜索). kdTree概念 kd-tree或者k维树是计算机科学中使用的一种数据结构,用来组织表示k维空间中点的集合.它是一种带有其他约束条件的二分查找树.Kd-tree对于区间和近邻搜索十分有用.一般位于三维空间中的邻

  • 关于antd tree 和父子组件之间的传值问题(react 总结)

    项目需求:点击产品树节点时获取该节点的所有父节点,同时回填表格的搜索条件,完成搜索功能,搜索结果展示在下方的table中. 写了三个组件: 现在有个业务场景交互:在orderTree组件中点击树节点,获取当前节点以及所有的父节点的Id 放入一个对象arrKeys中,并在orderForm组件中使用(回填类型下拉选择框,objId对象作为查询接口的入参) 现在可以分部解决问题: 1.首先获取点击的树节点以及所有父节点的id ---arrKeys 2.在点击树节点获取当前节点以及所有父级节点之后,通

  • 关于antd tree和父子组件之间的传值问题(react 总结)

    项目需求:点击产品树节点时获取该节点的所有父节点,同时回填表格的搜索条件,完成搜索功能,搜索结果展示在下方的table中. 写了三个组件: 现在有个业务场景交互:在orderTree组件中点击树节点,获取当前节点以及所有的父节点的Id 放入一个对象arrKeys中,并在orderForm组件中使用(回填类型下拉选择框,objId对象作为查询接口的入参) 现在可以分部解决问题: 1.首先获取点击的树节点以及所有父节点的id ---arrKeys 2.在点击树节点获取当前节点以及所有父级节点之后,通

  • vue组件之间进行传值的方法

    目录 前言 1.父组件向子组件进行传值 2.子组件向父组件进行传值 3.非父子组件之间的传值 总结 前言 目前在做vue的项目,用到了子组件依赖其父组件的数据,进行子组件的相关请求和页面数据展示,父组件渲染需要子组件通知更新父组件的state,父子组件之间的传值一般有三种方法: 父传子子传父非父子传值 注意: 父子组件的关系可以总结为 prop 向下传递,事件向上传递.父组件通过 prop 给子组件下发数据,子组件通过事件给父组件发送消息.  接下来,我们会通过实例代码来看的更清晰,理解更容易:

  • 通过实例讲解vue组件之间的传值

    目录 前言 1.父组件向子组件进行传值 2.子组件向父组件进行传值 3.非父子组件之间的传值 总结 前言 目前在做vue的项目,用到了子组件依赖其父组件的数据,进行子组件的相关请求和页面数据展示,父组件渲染需要子组件通知更新父组件的state,父子组件之间的传值一般有三种方法: 父传子 子传父 非父子传值 注意: 父子组件的关系可以总结为 prop 向下传递,事件向上传递.父组件通过 prop 给子组件下发数据,子组件通过事件给父组件发送消息. 接下来,我们会通过实例代码来看的更清晰,理解更容易

  • vue2.0父子组件及非父子组件之间的通信方法

    1.父组件传递数据给子组件 父组件数据如何传递给子组件呢?可以通过props属性来实现 父组件: <parent> <child :child-msg="msg"></child>//这里必须要用 - 代替驼峰 </parent> data(){ return { msg: [1,2,3] }; } 子组件通过props来接收数据: 方式1: props: ['childMsg'] 方式2 : props: { childMsg: Arr

  • vuejs父子组件之间数据交互详解

    父子组件之间的数据交互遵循: props down - 子组件通过props接受父组件的数据 events up - 父组件监听子组件$emit的事件来操作数据 示例 子组件的点击事件函数中$emit自定义事件 export default { name: 'comment', props: ['issue','index'], data () { return { comment: '', } }, components: {}, methods: { removeComment: funct

  • Vue父子组件之间的通信实例详解

    在vue组件通信中其中最常见通信方式就是父子组件之中的通信,而父子组件的设定方式在不同情况下又各有不同.最常见的就是父组件为控制组件子组件为视图组件.父组件传递数据给子组件使用,遇到业务逻辑操作时子组件触发父组件的自定义事件.无论哪种组织方式父子组件的通信方式都是大同小异. 一.父组件到子组件通讯 父组件到子组件的通讯主要为:子组件接受使用父组件的数据,这里的数据包括属性和方法(String,Number,Boolean,Object, Array ,Function).vue提倡单项数据流,因

  • vue实现父子组件之间的通信以及兄弟组件的通信功能示例

    本文实例讲述了vue实现父子组件之间的通信以及兄弟组件的通信功能.分享给大家供大家参考,具体如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>www.jb51.net vue父子组件通信.兄弟组件通信</title> <style> *{ margin: 0; padding: 0; l

  • vuejs中父子组件之间通信方法实例详解

    本文实例讲述了vuejs中父子组件之间通信方法.分享给大家供大家参考,具体如下: 一.父组件向子组件传递消息 // Parent.vue <template> <div class="parent"> <v-child :msg="message"></v-child> </div> </template> <script> import VChild from './child.v

  • Vue非父子组件之间的通信方式详解

    目录 非父子组件的通信 1.Provide和Inject 1.1基本使用 1.2处理响应式数据(了解) 2.全局事件总线 总结 非父子组件的通信 此篇讲解的是, 在学习状态管理之前, 非父子间通信的方案 在开发中,我们构建了组件树之后,除了父子组件之间的通信之外,还会有非父子组件之间的通信. 这里我们主要讲两种方式: Provide/Inject: 全局事件总线: 1.Provide和Inject 1.1基本使用 Provide/Inject用于非父子组件之间共享数据: 比如有一些深度嵌套的组件

随机推荐