详述react + ant desgin自定义树的节点,对节点进行重命名新增删除等操作

这篇具有很好参考价值的文章主要介绍了详述react + ant desgin自定义树的节点,对节点进行重命名新增删除等操作。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、自定义节点

        使用ant design中的Tree组件,基础树形组件只需要将treeData属性绑定一个树形结构的值(treeData={treeData})即可:

详述react + ant desgin自定义树的节点,对节点进行重命名新增删除等操作,React,react.js,前端,javascript

        但是由于单纯的展示名称已经不能满足这里的需求,使用将treeData处理后的TreeNode加到Tree的内部,代码如下,其中onSelect在点击树节点时触发:

  // 点击节点,第一次点击节点是选中,第二次点击同一个节点是取消选中,用keys来判断是否有选中
  const onSelect = (keys, info) => {
    if (keys.length > 0) {
      setSelectNode(info.node);
    } else {
      setSelectNode({});
    }
  };

//...

      <Tree
        style={{ marginTop: "20px" }}
        showLine={false}
        showIcon={true}
        onSelect={onSelect}
      >
        {handleTreeData(treeData)}
      </Tree>

        获取treeData,笔者这里treeData的格式为:

      [{
        id:'1',
        name:'所有',
        count:'21',
        suffix:'江苏',
        childNodes:[
          {
            id:'1-1',
            name:'南京',
            count:'21',
            suffix:'',
            childNodes:[]
          }
        ]
      }]

        从接口获取:

  const _getTreeData= async () => {
    setTreeData([]);
    try {
      let result = await getTreeData();
      setTreeData(result);
    } catch (error) {
    }
  };

        下面笔者需要处理数据,由上面的代码可知,通过handleTreeData函数处理数据treeData。分析一下基础的树形结构,Tree的节点其实是TreeNode,对于每一节点treeNode,根据官网的介绍,只需要设置其title和key属性,一般key属性即为树形数据的节点id,由此递归出所有的TreeNode:

详述react + ant desgin自定义树的节点,对节点进行重命名新增删除等操作,React,react.js,前端,javascript

  //  重写树
  const handleTreeData = (treeData) => {
    return treeData?.map((treeNode) => handleNodeData(treeNode));
  };
  const handleNodeData = (treeNode) => {
    if (treeNode.toString() === "[object Object]") {
        treeNode.title = (
          <div>
            <span className="text-overflow" title={treeNode.name}>{treeNode.name}</span>
            <span>({treeNode.other.count}) _{treeNode.suffix}</span>
          </div>
        );

        return (
            <TreeNode title={treeNode.title} key={treeNode.id}>
                {treeNode?.childNodes?.map((n) => handleNodeData(n))}
            </TreeNode>
        );
    }
    return <TreeNode {...treeNode} />;
  };

        至此,该树已经按照笔者的需求展示:

详述react + ant desgin自定义树的节点,对节点进行重命名新增删除等操作,React,react.js,前端,javascript


 二、重命名节点

        给每个节点后面添加一个按钮,点击按钮将节点切换为编辑状态,默认是原节点名称,根据上文,很容易想到在handleNodeData()中在treeNode.title中添加编辑按钮,并绑定rename():

<Button onClick={() => rename()} size={"small"}>重命名</Button>

        此外,需要给每个节点增加isEditdefaultValue(用于取消重命名后使用原来的节点名称)的属性,isEdit为true表示编辑态,否则正常展示节点。初始化数据,将所有节点的isEdit全部置为false。defaultValue值为name的值

  // 设置不可编辑
  const setAllNotEdit = (arr) => {
    let data = [].concat(arr);
    data.forEach((val) => {
      val.isEdit = false;
      if (val.childNodes && val.childNodes.length) {
        setAllNotEdit(val.childNodes);
      }
    });
    return data;
  };
  // 查询组织树
  const _getTreeData= async () => {
    //...
      let data = setAllNotEdit(result);
      setTreeData(data);
    //...
  };

        点击重命名,触发rename():在树形数据中找到该节点数据(定义deepTree函数,用于找到目标节点数据,并将名为第三个入参的键值修改为第四个入参),将isEdit改为true。在handleNodeData中针对编辑态和常规态作出单独的节点定义:

  const deepTree = (arr, key, keyName, value, otherValue) => {
    let data = [].concat(arr);
    for (let i = 0; i < data.length; i++) {

      if (data[i].id === key) {
        data[i][keyName] = value;
      } else if (typeof otherValue === "boolean") {
        data[i][keyName] = otherValue;
      }
      if (data[i].childNodes && data[i].childNodes.length) {
        deepTree(data[i].childNodes, key, keyName, value, otherValue);
      }
    }
    return data;
  };
 
 // 重命名
  const rename = () => {
    if (selectNode && selectNode.key) {
      let data = deepTree(treeData, selectNode.key, "isEdit", true, false);
      setTreeData(data);
    } else {
      message.warning("请选择节点");
    }
  };

//...

const handleNodeData = (treeNode) => {
    if (treeNode.toString() === "[object Object]") {
      if (treeNode.isEdit) {
        treeNode.title = (
          <div>
            <input value={treeNode.name} onChange={(e) => { changeNodeName(e,treeNode.id); }}/>
            ({treeNode.count})
            _{treeNode.suffix}
            <Button onClick={() => { saveTreeNode(treeNode); }} size={"small"} type="link" >确定</Button>
            <Button onClick={() => { cancelRename(treeNode); }} size={"small"} type="link" >取消</Button>
          </div>
        );
      } else {
            //...
        }
        //...
    }
    return <TreeNode {...treeNode} />;
};

        到这里,当点击重命名按钮时,节点已经变为编辑态了,input后有确定和取消两个按钮。当在input中输入新名称,触发changeNodeName(),如果没有这一步,input的值将无法修改(因为始终绑定的是节点名称,节点名称没有改变过):

  // 修改节点名称
  const changeNodeName = (e, key) => {
    let data = deepTree(treeData, key, "name", e.target.value);
    setTreeData(data);
  };

        点击取消时,表示取消重命名,使用原来的名称。在节点数据中找到当前节点,将值修改为之前的值(这个值我们已经保存在defaultValue中了):

  // 取消修改节点名称
  const cancelRename = (treeNode) => {
    let dataHasReset = deepTree(
      treeData,
      treeNode.id,
      "name",
      treeNode.defaultValue
    );
    let data = setAllNotEdit(dataHasReset);
    setTreeData(data);
  };

        点击确定时,表示修改节点名。

  • 如果此时只需要页面的更新,那么只需要在节点数据中找到该节点,更新defaultValue:
  const saveTreeNode = (treeNode) => {
    let dataHasChangeDefaultVal = deepTree(
      treeData,
      treeNode.id,
      "defaultValue",
      treeNode.name
    );
    let data = setAllNotEdit(dataHasChangeDefaultVal);
    setTreeData(data);
  };
  • 如果调用接口更新节点,只需要调用接口,接口成功后重新加载树:
  // 保存修改的节点名称
  const saveTreeNode = async (treeNode) => {
    try {
      await updateNode({
        //...
      });
      _getTreeData();
    } catch (e) {
    }
  };

        在Tree控件中,点击一次节点,表示选中当前节点,再次点击,表示取消选中,但是当切换为编辑态的时候,我们可能多次点击,为了防止数据丢失,修改onSelect如下(其中dataref是TreeNode的props):

  // 点击节点
  const onSelect = (keys, info) => {
    if (keys.length > 0 || info.node?.dataRef?.isEdit) {
      setSelectNode(info.node);
    } else {
      setSelectNode({});
    }
  };

const formatNodeData = (treeNode) => {
    if (treeNode.toString() === "[object Object]") {
      //...
      return (
        <TreeNode title={treeNode.title} key={treeNode.id} dataRef={treeNode}>
          {treeNode?.childNodes?.map((d) => formatNodeData(d))}
        </TreeNode>
      );
    }
    return <TreeNode {...treeData} />;
})

        在对选中的节点进行重命名之后,虽然树是新的树了,但是保存了节点选中的状态,也保存了被选的节点数据,为了防止数据不同步造成的误会,这里笔者每次得到新的树时,就会把选中的状态去掉,选中的数据也置空。选中的数据置空只需要setSelectNode({})即可。但是去掉选中的状态就要求使用Tree控件的另一个属性:selectedKeys,表示选中的节点,当加上这个属性,当点击节点后,需要将绑定的值也更新:

  // 点击节点
  const onSelect = (keys, info) => {
    setSelectedKeys(keys);
    //...
  };

//...
      <Tree
        showLine={false}
        showIcon={true}
        defaultExpandAll={true}
        onSelect={onSelect}
        selectedKeys={selectedKeys}
      >
        {formatTreeData(treeData)}
      </Tree>

        至此,重命名节点名称已经实现。


三、新增节点

        笔者这里添加的是子节点,兄弟节点也类似,不再赘述。

        所谓新增节点,其实就是处理树形结构的数据。

  • 如果此时只需要页面的更新,在当前选中节点的childNodes中增加一个对象,所以,递归找到选中的节点,push一个新节点即可:
  const onAdd = (arr) => {
    let data = [].concat(arr);
    data.forEach((item) => {
      if (item.id === selectNode.key) {
        if (!item.childNodes) {
          item.childNodes = [];
        }
        item.childNodes.push({
          name: "新节点",
          defaultValue: "新节点",
          id: selectNode.key + Math.random(100),
          suffix:'',
          count:'',
          isEditable: false,
          childNodes: [],
        });
        return;
      }
      if (item.childNodes) {
        onAdd(item.childNodes);
      }
    });
    return data;
  };
  const addNode = () => {
    if (selectNode && selectNode.key) {
        let data = onAdd(treeData);
        setTreeData(data);
    } else {
      message.warning("请选择节点");
    }
  };
  • 如果调用接口更新节点,只需要调用接口,接口成功后重新加载树:
  // 添加下级
  const addNode = async () => {
    if (selectNode && selectNode.key) {
        try {
          let result = await addNode({
            //...
          });
          _getTreeData();
        } catch (e) {
        }
    }
  };

        至此,新增节点已经实现。


四、删除节点

        与新增节点相对,删除节点是在数据中找到选中节点,从childNodes中删除元素。同样从两种场景出发:

  • 如果此时只需要页面的更新,在当前选中节点的childNodes中删除一个对象,所以,递归找到选中的节点,splice即可:
  const onDelete = (arr) => {
    arr.forEach((item, index) => {
      if (item.id === selectNode.key) {
        arr.splice(index, 1);
        return;
      }
      if (item.childNodes) {
        onDelete(item.childNodes);
      }
    });
    return arr;
  };
  const delNode = () => {
    if (selectNode && selectNode.key) {
        let data = onDelete(treeData);
        setTreeData([].concat(data));
        setSelectNode({});
    } else {
      message.warning("请选择节点");
    }
  };
  • 如果调用接口更新节点,只需要调用接口,接口成功后重新加载树:
  // 删除节点
  const delNode = () => {
    if (selectNode && selectNode.key) {
      try {
        let result = await deleteNode({
           //...
        });
        _getTreeData();
      } catch (e) {}
    } else {}
  };

        至此,删除节点已经实现。


总结

        本篇详述了对于react + ant design的树形控件的自定义节点,以及对节点的增删改,如有建议,欢迎指教~文章来源地址https://www.toymoban.com/news/detail-729356.html

到了这里,关于详述react + ant desgin自定义树的节点,对节点进行重命名新增删除等操作的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • react ant icon的简单使用

    refer: 快速上手 - Ant Design 1.引入ant 2.在页面引用: 如果想要引入多个icon,可以这样书写: 上面这行代码就是在页面引入了ant的icon StarOutlined,在页面显示的是一个空心的星星 3.在需要的位置使用这个icon 上面这段代码是在查看这个button左侧增加了这个星星icon,如果你想设置c

    2024年02月14日
    浏览(36)
  • React安装ant design组件库,并使用

    ant design是一个很棒的组件库,官方地址:快速上手 - Ant Design 但是如何在React里面用起来,好像并不是很顺畅,没有像Vue里面那么友好,因为我踩过这个坑,虽然安装很简单,但是想要出样式,还是有点步骤的。 npm命令: yarn命令: pnpm命令: 千万不要简单的只看官方的文档

    2024年02月14日
    浏览(48)
  • react ant table 根据接口动态渲染表头

    使request获取list,renderFormItem回调里面第二个参数中就有request的返回值,根据这个去渲染就可以了

    2024年02月16日
    浏览(41)
  • Ant react 组件报错解决整理 4.4

    1、[antd: Drawer] `visible` is deprecated which will be removed in next major version, please use `open` instead. 解决:将Drawer组件 visble 改为 open; 2、[antd: Descriptions] Sum of column `span` in a line not match `column` of Descriptions.  解决:默认一行显示三个,一个占位一行,如果想占多列,请使用表格。 3、[a

    2024年02月12日
    浏览(39)
  • 为React Ant-Design Table增加字段设置

    最近做的几个项目经常遇到这样的需求,要在表格上增加一个自定义表格字段设置的功能。就是用户可以自己控制那些列需要展示。 在几个项目里都实现了一遍,每个项目的需求又都有点儿不一样,迭代了很多版,所以抽时间把这个功能封装了个组件:@silverage/table-custom,将

    2024年02月05日
    浏览(59)
  • react ant add/change created_at

    1.引入ant的 Table 2.获得接口的数据的时候增加上创建时间 3.对接口的数据进行处理 这样会显示数据: 需要修改为北京时间: 最后做出这样的修改:(显示为北京时间:2023/7/24 15:10:38)  

    2024年02月14日
    浏览(31)
  • React——Ant Design组件库Message全局提示的使用

    官网推荐使用Hook调用的方法         这种方法只能在本页显示,如果显示后跳转页面就不会显示。因为{contextHolder}是写在本页面的。如果需要跳转页面可以用promise调用 传递的参数依次为,提示信息、显示时间、关闭后触发的回调

    2024年02月11日
    浏览(44)
  • 【数据结构】二叉树的节点总个数、叶子节点个数、第K层节点个数、二叉树的深度

    目录 1.结点总个数 1.1 局部静态变量法 思维 代码 不足之处 2.传指针法 程序代码 3.递归法 思想 程序代码 详细过程 2.叶子节点个数 思想 程序代码 3.第K层节点个数 思想 程序代码 4.二叉树深度 思想 程序代码         求二叉树节点总个数、叶子节点个数、第k层节点个数、二叉

    2024年02月02日
    浏览(40)
  • React 基于Ant Degisn 实现table表格列表拖拽排序

     代码:

    2024年01月18日
    浏览(44)
  • react ant-design实现导航菜单menu的路由设置/切换页面

    ant-design版本是5.1.1,路由版本是v6的 新版本的导航菜单路由设置与旧版的不太一样,刚开始的时候甚至不知道该怎么写 实现效果: 代码: 首先,给导航菜单的menu添加点击事件 修改item,通过设置点击事件获取点击后的key值(key值即路由跳转的页面) 打印出来看看 获取到的

    2024年02月12日
    浏览(58)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包