实战react+ts+antd遇见的问题之自定义树形结构

目录

  • 自定义编辑树
  • 搜索树形结构
    • 搜索算法原理
  • 实时更改数据界面不随之发生变化

自定义编辑树

需求要求在每个节点的后面加上新增,编辑,删除按钮,并且能够点击编辑title的显示变成input输入框,antd的案例中没有这种情况,但是antd的api中给了titleRender可以自定义title样式。
在这里插入图片描述

<Tree
			...
            titleRender={onTitleRender}
			...
        >
</Tree>
 const onTitleRender = (item: any) => {      //  title渲染函数
        let content
        let icon
        let beforeIcon
        if (item.key === pickedEdit) {
            content = (<Input
                // value={item.title}
                defaultValue={item.title}
                onChange={(e) => onChange(e, item.key)}
                onPressEnter={(e) => onPressEnter(e, item.key)}
                onBlur={(e) => onPressEnter(e, item.key)}
            />)
        } else {
            content = (<div onClick={(e) => chooseContent(e, item.title)}>{item.title}</div>)
        }


        if (!item.isLeaf) { //  该节点为父节点
            beforeIcon = (<FolderOpenTwoTone twoToneColor="#cdb228" style={{ marginRight: '5px' }} />)
            icon = (
                <span style={{ display: 'flex' }}>
                    <PlusOutlined style={{ marginLeft: 10, color: '#409EFF' }} onClick={() => onAdd(item.key)} />
                    <EditOutlined style={{ marginLeft: 10, color: '#409EFF' }} onClick={() => onEdit(item.key)} />
                    <CloseOutlined style={{ marginLeft: 10, color: '#409EFF' }} onClick={() => onDelete(item.key)} />
                </span>
            )

        } else {    //  该节点为叶子节点
            beforeIcon = (<FileTextOutlined style={{ marginRight: '5px' }} />)
            icon = (
                <span style={{ display: 'flex' }}>
                    <EditOutlined style={{ marginLeft: 10, color: '#409EFF' }} onClick={() => onEdit(item.key)} />
                    <CloseOutlined style={{ marginLeft: 10, color: '#409EFF' }} onClick={() => onDelete(item.key)} />
                </span>
            )
        }
        return (
            <div style={{ display: 'flex', alignItems: 'center' }}>
                {beforeIcon}
                {content}
                {icon}
            </div>
        );

    };

这里我设置了一个全局变量pickedEdit来记录当前正在编辑的节点的key,当编辑的key有值后,key相等的title就会变成input框
我这里的判断是因为我们要求树只有三层,所以不给叶子节点add功能,也用不同的图标区分是否是叶子节点。

搜索树形结构

首先,返回的node肯定要加一个
其次,是搜索框change内容时触发的函数,如下

// 搜索框的change事件触发函数
    const onChangeSearch = (e: any) => {
        const { value } = e.target;
        const expandedKeys = dataList
            .map((item: any) => {
                if (item.title.indexOf(value) > -1) {
                    return getParentKey(item.key, treeData);
                }
                return null;
            })
            .filter((item: any, i: any, self: any) => item && self.indexOf(item) === i);

        setExpandedKeys(expandedKeys);
        setSearchValue(value);
        setAutoExpandParent(true);
    };
//  生成key的数组
    const generateList = (data: any) => {
        for (let i = 0; i < data.length; i++) {
            const node = data[i];
            const { key, title } = node;
            dataList.push({ key, title: title });
            if (node.children) {
                generateList(node.children);
            }
        }
    };
    generateList(treeData);
    
    //  查询父节点的key
    //@ts-ignore
    const getParentKey = (key: any, tree: any) => {
        let parentKey;
        for (let i = 0; i < tree.length; i++) {
            const node = tree[i];
            if (node.children) {
                if (node.children.some((item: any) => item.key === key)) {
                    parentKey = node.key;
                } else if (getParentKey(key, node.children)) {
                    parentKey = getParentKey(key, node.children);
                }
            }
        }
        return parentKey;
    };

最后也是最最重要的:搜索算法

// 循环遍历搜索关键字
    const loop = (data: any) =>
        data.map((item: any) => {
            //  将title分成三部分,中间的是搜索命中的内容
            const index = item.title.indexOf(searchValue);
            const beforeStr = item.title.substr(0, index);
            const afterStr = item.title.substr(index + searchValue.length);
            const title =
                index > -1 ? (
                    <span>
                        {beforeStr}
                        <span style={{ color: '#f50' }}>{searchValue}</span>
                        {afterStr}
                    </span>
                ) : (
                    <span>{item.title}</span>
                );
            if (item.children) {
                return { title, key: item.key, children: loop(item.children) };
            }

            return {
                title,
                key: item.key,
                isLeaf: item.isLeaf
            };
        });

搜索算法原理

将title分为三部分,beforeStr,index和afterStr,其中index是搜索的内容;
如果index存在,就将index的内容样式改变,变成红色。
这里的搜索顺序是深度优先。

实时更改数据界面不随之发生变化

联调的时候突然发现,改完数据后上传,然后用setState更新treedata,这时界面上的数据没有变化,没更新?
想起来之前准备面试的时候学的深拷贝和浅拷贝,tree在ts中是以object类型保存的,那么setState会不会只是个浅拷贝,只存了这个变量的地址,所以它地址没变就没有重新渲染,那么就可以采用一些方式让他进行深拷贝,也可以改变一下它的地址,比如下面我采取的方法:

let temp = [...treeData]
setTreeData(temp)

你可能感兴趣的:(react,react.js,javascript,前端)