React + antd 可编辑下拉树

如图

import React, { Component } from 'react';
import {Tree, Icon, TreeSelect, Col, Row, Button, Popconfirm, message} from 'antd';
import styles from '../style/tree.less';

const { TreeNode } = Tree;
class EditableTree extends Component {
    constructor(props){
        super(props)
        this.state = {
            expandedKeys: [],
            data: [
                // {
                //     modelGroupName: 'Root',
                //     defaultValue: 'Root',
                //     first: true,
                //     value: '0',
                //     key: '0',
                //     parentKey: '0',
                //     isEditable: false
                // }
            ],
            selectTreeVal: '',
            showTitle: ''
        }
        this.changeTree = this.changeTree.bind(this)
    }
    componentDidMount(){
    }
    isNullUndefined(val){
       if (typeof val === 'undefined' || val === '' || val === null) {
            return true;
      } else {
        return false;
      }
    }
    renderTreeNodes = data => data.map((item) => {
        if (item.isEditable) {
            item.title = (
                <div onClick={(e) => {e.stopPropagation()}} id="treeDiv">
                    <input
                        className={styles.inputField}
                        value={item.modelGroupName}
                        onChange={(e) => this.onChange(e, item, data)}
                    />
                    <Icon type='close' className='iconSty' onClick={(e) => this.onClose(item.key, item, data)} />
                    <Popconfirm
                        getPopupContainer={() => document.getElementById('treeDiv')}
                        title="确定要保存吗?"
                        onConfirm={(e) => this.onSave(item, data)}
                        okText="确定"
                        placement="bottomLeft"
                        cancelText="取消"
                    >
                        <Icon type='check' className='iconSty' />
                    </Popconfirm>
                </div>
            );
        } else {
            item.title = (
                <div id='treeDivdel' className={styles.titleContainer} onClick={() => this.onChangeTree(item)}>
                    <div>
                        {item.modelGroupName}
                    </div>
                    <div className={styles.operationField} >
                        {item.first ? null : (
                        <Icon className='iconSty' type='edit' onClick={(e) => {e.stopPropagation(); this.onEdit(data, item.key)}} />
                        )}
                        <Icon className='iconSty' type='plus' onClick={(e) => {e.stopPropagation(); this.onAdd(data, item.key)}} />
                        {item.first ? null : (
                            <Popconfirm
                                getPopupContainer={(triggerNode) => triggerNode.parentElement}
                                title="确定要删除吗?"
                                placement="bottomLeft"
                                onConfirm={(e) => {e.stopPropagation(); this.onDelete(data, item)}}
                                onCancel={(e) => e.stopPropagation()}
                                okText="确定"
                                cancelText="取消"
                            >
                                <Icon className='iconSty' type='minus' onClick={(e) => e.stopPropagation()} />
                            </Popconfirm>

                        )}
                    </div>
                </div>
            )
        }

        if (item.children) {
            return (
                <TreeNode title={item.title} key={item.key} value={item.value}>
                    {this.renderTreeNodes(item.children)}
                </TreeNode>
            );
        }

        return <TreeNode {...item} />;
    })


    onAdd = (data, e) => {
        console.log('add', data);
        this.addNode(e, data);
        this.setState({
            expandedKeys: this.state.expandedKeys,
            data: data
        });
    }

    addNode = (key, data) => data.map((item, index) => {
        if (item.key === key) {
            if (item.children) {
                item
                    .children
                    .push({
                        modelGroupName: '',
                        defaultValue: '',
                        first: false,
                        value: Math.random().toString(36).substring(2, 6),
                        key: Math.random().toString(36).substring(2, 6),
                        parentKey: key,
                        parentId: item.id ? item.id : '',
                        parentPId: item.pid ? item.pid : '',
                        isEditable: true
                    });
            } else {
                item.children = [];
                item
                    .children
                    .push({
                        modelGroupName: '',
                        first: false,
                        defaultValue: '',
                        value: Math.random().toString(36).substring(2, 6),
                        key: Math.random().toString(36).substring(2, 6),
                        parentKey: key,
                        parentId: item.id ? item.id : '',
                        parentPId: item.pid ? item.pid : '',
                        isEditable: true
                    });
            }
            return;
        }
        if (item.children) {
            this.addNode(key, item.children)
        }
    })

    onDelete = (data, item) => {
        // console.log('delete');
        if (item.id) {
            this.props.sendDelModelList(item)
        } else {
            this.deleteNode(item.key, data);
            this.setState({
                data: data
            });
        }
    }

    deleteNode = (key, data) => data.map((item, index) => {
        if (item.key === key) {
            data.splice(index, 1);
        } else {
            if (item.children) {
                this.deleteNode(key, item.children)
            }
        }
    })

    onEdit = (data, key) => {
        // console.log('edit');
        this.editNode(key, data);
        this.setState({
            data: data
        });
    }

    editNode = (key, data) => data.map((item) => {
        if (item.key === key) {
            item.isEditable = true;
        } else {
            item.isEditable = false;
        }
        item.modelGroupName = item.defaultValue; // 当某节点处于编辑状态,并改变数据,点击编辑其他节点时,此节点变成不可编辑状态,value 需要回退到 defaultvalue
        if (item.children) {
            this.editNode(key, item.children)
        }
    })

    onClose = (key, item, data) => {
       // console.log('close');
        this.closeNode(key, item.defaultValue, data);
        this.setState({
            data: data
        });
    }

    closeNode = (key, defaultValue, data) => data.map((item) => {
        item.isEditable = false;
        if (item.key === key) {
            item.modelGroupName = defaultValue;
        }
        if (item.children) {
            this.closeNode(key, defaultValue, item.children)
        }
        if (this.isNullUndefined(item.modelGroupName) && this.isNullUndefined(item.defaultValue)){
            this.deleteNode(item.key, data);
        }
    })

    onSave = (item, data) => {
        // console.log('save')
        // console.log(item)
         if (this.isNullUndefined(item.modelGroupName)){
            return message.warning('请填写模型名称');
        }
        this.saveNode(item.key, data);
        this.setState({
            data: data
        });
        this.props.sendAddModelList(item) // 调用接口的方法
    }

    saveNode = (key, data) => data.map((item) => {
        if (item.key === key) {
            item.modelGroupName = item.modelGroupName;
            item.defaultValue = item.modelGroupName;
        }
        if (item.children) {
            this.saveNode(key, item.children)
        }
        item.isEditable = false;
    })

    onChange = (e, item, data) => {
        this.changeNode(item.key, e.target.value, data);
        this.setState({
            data: data
        });
    }

    changeNode = (key, value, data) => data.map((item) => {
        if (item.key === key) {
            item.modelGroupName = value;
        }
        if (item.children) {
            this.changeNode(key, value, item.children)
        }
    })
    onChangeTree = (item) => {
       console.log(item, "====");
        // this.setState({
        //     selectTreeVal: value
        // })
    };
    changeTree(e){
        if (this.isNullUndefined(e)) {
            this.props.selectModel({ modelGroupName: '' })
        }
    }
    render() {
        const { modelData } = this.props
        return (
            <div >
               <TreeSelect onChange={this.changeTree} treeDefaultExpandAll allowClear style={{ width: '100%' }} >
                            {this.renderTreeNodes(modelData)}
                        </TreeSelect>
            </div>
        )
    }
}

export default EditableTree;

css 样式 新建一个样式 tree.less


 .inputField {
     border: none;
     border-bottom: 1px solid;
     background: none;
     line-height: normal;
     min-width: 50px;
     outline: none;
     &:focus {
         outline: none;
     }
 }

 #treeDivdel{
     display: flex;
     justify-content: space-between;
 }
 .titleContainer {
     .operationField {
         visibility: hidden;
     }

     &:hover {
         .operationField {
             visibility: visible;
         }
     }
 }

 :global {
     .ant-tree li .ant-tree-node-content-wrapper:hover {
         background-color: unset;
     }
 }
 .iconSty{
     margin-left: 10px;
     font-size: 12px;
     border: 2px solid #e8e8e8;
     color: rgba(0, 0, 0, 0.65);
     background: #e8e8e8;
     border-radius: 10px;
     padding: 5px;
 }

:global {
    .ant-select-selection-selected-value{
        .iconSty {
            display: none;
        }
    }
}

参考 https://github.com/JerryMissTom/react-editable-tree/blob/master/EditableTree.js

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下拉多选可以使用antd-mobile的CheckboxItem组件来实现。具体代码如下: ```jsx import React, { useState } from 'react'; import { List, Checkbox } from 'antd-mobile'; const CheckboxItem = Checkbox.CheckboxItem; const options = [ { label: '选项1', value: '1' }, { label: '选项2', value: '2' }, { label: '选项3', value: '3' }, { label: '选项4', value: '4' }, ]; const MultipleSelect = () => { const [selectedValues, setSelectedValues] = useState([]); const handleCheckboxChange = (value) => { const currentIndex = selectedValues.indexOf(value); const newValues = [...selectedValues]; if (currentIndex === -1) { newValues.push(value); } else { newValues.splice(currentIndex, 1); } setSelectedValues(newValues); }; return ( <List> {options.map((option) => ( <CheckboxItem key={option.value} checked={selectedValues.indexOf(option.value) !== -1} onChange={() => handleCheckboxChange(option.value)} > {option.label} </CheckboxItem> ))} </List> ); }; export default MultipleSelect; ``` 上面的代码中,我们定义了一个`options`数组来存储选项列表。然后使用`useState`来管理已选中的值,初始值为空数组。在`handleCheckboxChange`方法中,我们根据选项的值来判断它是否已经被选中,如果已经被选中,则从已选中的值数组中删除该值,否则将该值添加到已选中的值数组中。最后通过`setSelectedValues`更新已选中的值数组。 在渲染时,我们遍历选项列表,并为每个选项渲染一个`CheckboxItem`组件。我们使用`checked`属性来判断该选项是否已经被选中,使用`onChange`事件来处理选项的选择和取消选择操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值