【Ant-Desgin-React 穿梭框】表格穿梭框,树穿梭框的用法

Antd Desgin 穿梭框

  • 普通用法
  • 高级用法-表格穿梭框组件
  • 高级用法-树穿梭框组件

普通用法

/* eslint-disable no-unused-vars */
import React, { useEffect, useState } from 'react'
import { Space, Transfer } from 'antd'

// Antd的穿梭框组件Mock数据
const mockData = Array.from({
  length: 20
}).map((_, i) => ({
  key: i.toString(),
  title: `content${i + 1}`,
  description: `description of content${i + 1}`,
  disabled: i % 3 < 1 // 禁用某项
}))

// 筛选出ID数组
const initialTargetKeys = mockData.filter(item => Number(item.key) > 10).map(item => item.key)

const App = () => {
  // 设置目标键数组
  const [targetKeys, setTargetKeys] = useState(initialTargetKeys)
  // 设置选中的键数组
  const [selectedKeys, setSelectedKeys] = useState([])

  useEffect(() => {
    console.log('模拟数据', mockData)
  }, [])

  const onChange = (nextTargetKeys, direction, moveKeys) => {
    console.log('==========Start Change==========')
    console.log('targetKeys:', nextTargetKeys) // 下一次的目标键数组,即移动后的目标列表
    console.log('direction:', direction) // 移动的方向,可以是'left'或'right',表示从左侧列表移动到右侧列表或从右侧列表移动到左侧列表
    console.log('moveKeys:', moveKeys) // 移动的键数组,即移动的项
    console.log('==========End Change==========')
    setTargetKeys(nextTargetKeys)
  }

  const onSelectChange = (sourceSelectedKeys, targetSelectedKeys) => {
    console.log('==========Start SelectChange==========')
    console.log('sourceSelectedKeys:', sourceSelectedKeys) // 源列表中选中的键数组
    console.log('targetSelectedKeys:', targetSelectedKeys) // 目标列表中选中的键数组
    console.log('==========End SelectChange==========')
    setSelectedKeys([...sourceSelectedKeys, ...targetSelectedKeys])
  }

  const onScroll = (direction, e) => {
    console.log('==========Start Scroll==========')
    console.log('direction:', direction) // 滚动的方向,可以是'left'或'right',表示向左滚动或向右滚动
    console.log('target:', e.target) // 滚动事件对象,包含了滚动的相关信息,如滚动的目标等
    console.log('==========End Scroll==========')
  }

  console.log('==========Start Search==========')
  const handleSearch = (dir, value) => {
    // dir 表示搜索框所在的列表,可以是'left'或'right',表示在源列表或目标列表中搜索\
    // value 表示搜索框中的值
    console.log('search:', dir, value)
  }
  console.log('==========End Search==========')

  return (
    <div className="App">
      <Space>
        <Transfer
          dataSource={mockData} // 数据源,即需要在两个列表之间移动的数据列表
          titles={['Source', 'Target']} // 列表的标题,包括源列表和目标列表的标题
          targetKeys={targetKeys} // 目标列表中的键数组,表示当前已经选中的项的键数组
          selectedKeys={selectedKeys} // 当前选中的项的键数组,用于在两个列表之间移动项时的状态管理
          onChange={onChange} // 当目标列表中的键数组改变时触发的事件回调函数
          onSelectChange={onSelectChange} // 当源列表和目标列表中的选中项改变时触发的事件回调函数
          onScroll={onScroll} // 当滚动时触发的事件回调函数
          onSearch={handleSearch} // 当搜索框中的值改变时触发的事件回调函数
          render={item => item.title} // 定义如何渲染每个数据项,返回一个React元素
          oneWay // 是否只允许从左侧列表向右侧列表移动数据,默认为false
          showSearch // 是否显示搜索框,默认为false
          pagination // 是否显示分页,默认为false,一般在大数据量下使用
        />
        {/* 自定义状态 */}
        <Transfer status="error" />
        <Transfer status="warning" showSearch />
      </Space>
    </div>
  )
}

export default App

在这里插入图片描述

高级用法-表格穿梭框组件

/* eslint-disable react/prop-types */
/* eslint-disable no-unused-vars */
import React, { useState } from 'react'
import { Space, Switch, Table, Tag, Transfer } from 'antd'

// leftColumns 表示左侧表格的列,rightColumns表示右侧表格的列,restProps表示其他属性
const TableTransfer = ({ leftColumns, rightColumns, ...restProps }) => (
  // 渲染Transfer组件
  <Transfer {...restProps}>
    {({
      direction, // 数据传输方向(左或右)
      filteredItems, // 经过搜索过滤后的项
      onItemSelect, // 选中项时的回调函数
      onItemSelectAll, // 全选项时的回调函数
      selectedKeys: listSelectedKeys, // 已选中项的键数组
      disabled: listDisabled // 列表是否被禁用的标志
    }) => {
      const columns = direction === 'left' ? leftColumns : rightColumns // 根据传输方向选择表格列
      const rowSelection = {
        getCheckboxProps: () => ({
          disabled: listDisabled // 设置复选框是否禁用
        }),
        onChange(selectedRowKeys) {
          onItemSelectAll(selectedRowKeys, 'replace') // 全选/取消全选时的操作
        },
        selectedRowKeys: listSelectedKeys, // 已选中项的键数组
        selections: [Table.SELECTION_ALL, Table.SELECTION_INVERT, Table.SELECTION_NONE] // 表格行选择器
      }
      return (
        <Table
          rowSelection={rowSelection} // 表格行选择器配置
          columns={columns} // 表格列配置
          dataSource={filteredItems} // 数据源
          size="small" // 表格尺寸
          style={{
            pointerEvents: listDisabled ? 'none' : undefined // 根据列表是否禁用设置CSS样式
          }}
          onRow={({ key, disabled: itemDisabled }) => ({
            // 表格行的事件处理函数
            onClick: () => {
              if (itemDisabled || listDisabled) {
                // 如果项被禁用或列表被禁用,则不执行操作
                return
              }
              onItemSelect(key, !listSelectedKeys.includes(key)) // 选中/取消选中项时的操作
            }
          })}
        />
      )
    }}
  </Transfer>
)

const mockTags = ['cat', 'dog', 'bird'] // 模拟标签数据
const mockData = Array.from({
  // 生成模拟数据
  length: 20
}).map((_, i) => ({
  key: i.toString(), // 唯一键
  title: `content${i + 1}`, // 标题
  description: `description of content${i + 1}`, // 描述
  tag: mockTags[i % 3] // 标签
}))
// 表格列配置
const columns = [
  {
    dataIndex: 'title',
    title: 'Name'
  },
  {
    dataIndex: 'tag',
    title: 'Tag',
    render: tag => (
      <Tag
        style={{
          marginInlineEnd: 0
        }}
        color="cyan"
      >
        {tag.toUpperCase()}
      </Tag>
    )
  },
  {
    dataIndex: 'description',
    title: 'Description'
  }
]
const Default = () => {
  const [targetKeys, setTargetKeys] = useState([]) // 目标键数组的状态及其更新函数
  const [disabled, setDisabled] = useState(false) // 禁用状态及其更新函数
  const onChange = nextTargetKeys => {
    // 目标键数组变化时的处理函数
    setTargetKeys(nextTargetKeys) // 更新目标键数组
  }
  const toggleDisabled = checked => {
    // 切换禁用状态的处理函数
    setDisabled(checked) // 更新禁用状态
  }
  return (
    <>
      <TableTransfer // 表格数据传输组件
        dataSource={mockData} // 数据源
        targetKeys={targetKeys} // 目标键数组
        disabled={disabled} // 是否禁用
        showSearch // 是否显示搜索框
        showSelectAll={false} // 是否显示全选按钮
        onChange={onChange} // 目标键数组变化时的回调函数
        filterOption={(
          inputValue,
          item // 自定义搜索过滤函数
        ) => item.title.indexOf(inputValue) !== -1 || item.tag.indexOf(inputValue) !== -1}
        leftColumns={columns} // 左侧表格列配置
        rightColumns={columns} // 右侧表格列配置
      />
      <Space
        style={{
          marginTop: 16
        }}
      >
        {/* 开关组件,用于切换禁用状态 */}
        <Switch unCheckedChildren="disabled" checkedChildren="disabled" checked={disabled} onChange={toggleDisabled} />
      </Space>
    </>
  )
}
export default Default

在这里插入图片描述

高级用法-树穿梭框组件

未完善

TreeTransfer.jsx 树穿梭框组件

/* eslint-disable no-unused-vars */
/* eslint-disable react/prop-types */
import React, { useEffect, useState } from 'react'
import { Transfer, Tree } from 'antd'

const generateTree = (treeNodes = [], checkedKeys = [], parentKeys = []) =>
  treeNodes.map(({ children, ...props }) => {
    const updatedProps = {
      ...props,
      disabled: checkedKeys.includes(props.key),
      children: generateTree(children, checkedKeys, parentKeys.concat(props.key))
    }

    // 父节点如果被选中,则添加所有子节点到 checkedKeys
    if (checkedKeys.includes(props.key)) {
      updatedProps.children.forEach(child => {
        if (!checkedKeys.includes(child.key)) {
          checkedKeys.push(child.key)
        }
      })
    }

    return updatedProps
  })

const TreeTransfer = ({ dataSource, ...restProps }) => {
  const [selectedKeys, setSelectedKeys] = useState([])
  const [targetKeys, setTargetKeys] = useState([])

  useEffect(() => {
    console.log(selectedKeys, 'selectedKeys')
  }, [selectedKeys, setSelectedKeys])

  // 子节点全部选中时,让父节点也会被选中
  // key 表示当前节点,checkedKeys 是当前目标源keys数组,dataSource 是数据数组
  const updateParentKeys = (key, checkedKeys, dataSource) => {
    console.log(key, '当前节点', checkedKeys, '当前目标源keys数组', dataSource, '数据数组')
    // 对 checkedKeys 做浅拷贝,以避免直接修改原数组
    const updatedKeys = [...checkedKeys]
    // 查找包含指定子节点键 key 的父节点
    const parentNode = dataSource.find(item => item.children && item.children.some(child => child.key === key))
    if (parentNode) {
      // 如果找到了父节点
      // 检查父节点的所有子节点是否都在 updatedKeys 中
      const allChildrenChecked = parentNode.children.every(child => updatedKeys.includes(child.key))
      // 如果所有子节点都被选中且父节点未被选中,则将父节点添加到 updatedKeys 中
      if (allChildrenChecked && !updatedKeys.includes(parentNode.key)) {
        updatedKeys.push(parentNode.key)
      } else if (!allChildrenChecked && updatedKeys.includes(parentNode.key)) {
        // 如果存在未被选中的子节点且父节点被选中,则从 updatedKeys 中移除父节点
        updatedKeys.splice(updatedKeys.indexOf(parentNode.key), 1)
      }
      // 递归更新父节点的父节点,确保所有相关节点的选中状态都被正确更新
      return updateParentKeys(parentNode.key, updatedKeys, dataSource)
    }
    // 如果没有找到父节点,则直接返回 updatedKeys
    return updatedKeys
  }

  const handleCheck = (checkedKeys, { node: { key, children } }) => {
    let cKeys = [...selectedKeys] // 复制当前已选择的键数组
    // 如果点击的节点已经在已选择数组中,则从数组中移除
    if (cKeys.includes(key)) {
      cKeys = cKeys.filter(item => item !== key)
      if (children && children.length > 0) {
        const checkList = dataSource
          .filter(item => item.key === key)
          .map(item => {
            return [key, ...item.children.map(child => child.key)]
          })
          .flat()
        console.log(checkList, '取消选择的父节点')
        // 使用 Array.prototype.filter() 来移除整个节点数组
        cKeys = cKeys.filter(item => !checkList.includes(item))
      } else {
        // 如果点击的是子节点,则检查父节点是否需要从已选择数组中移除
        cKeys = updateParentKeys(key, cKeys, dataSource)
      }
    } else {
      // 将当前节点添加到已选择数组中
      cKeys.push(key)
      // 如果点击的是父节点,则同时将子节点也添加到已选择数组中
      if (children && children.length > 0) {
        children.forEach(child => {
          cKeys.push(child.key)
        })
      } else {
        // 如果点击的是子节点,则检查父节点是否需要添加到已选择数组中
        cKeys = updateParentKeys(key, cKeys, dataSource)
      }
    }

    setSelectedKeys(cKeys)
  }

  const onChange = (t, d, m) => {
    setTargetKeys(selectedKeys)
  }

  return (
    <Transfer
      {...restProps}
      targetKeys={targetKeys}
      selectedKeys={selectedKeys}
      dataSource={dataSource}
      onChange={onChange}
      render={item => item.title}
      showSelectAll={false}
      oneWay
    >
      {({ direction }) => {
        if (direction === 'left') {
          const checkedKeys = [...selectedKeys, ...targetKeys]
          return (
            <Tree
              blockNode
              checkable
              checkStrictly
              defaultExpandAll
              checkedKeys={checkedKeys}
              treeData={generateTree(dataSource, targetKeys)}
              onCheck={handleCheck}
              onSelect={handleCheck}
            />
          )
        }
      }}
    </Transfer>
  )
}

export default TreeTransfer

Index.jsx

/* eslint-disable no-unused-vars */
/* eslint-disable react/prop-types */
import React, { useState } from 'react'
import TreeTransfer from './dom';

const treeData = [
  {
    key: '0-0',
    title: '0-0'
  },
  {
    key: '0-1',
    title: '0-1',
    children: [
      {
        key: '0-1-0',
        title: '0-1-0'
      },
      {
        key: '0-1-1',
        title: '0-1-1'
      }
    ]
  },
  {
    key: '0-2',
    title: '0-2'
  },
  {
    key: '0-3',
    title: '0-3'
  },
  {
    key: '0-4',
    title: '0-4'
  }
]

const Index = () => {
  return <TreeTransfer dataSource={treeData} />
}
export default Index

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/571861.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CJSON工具类

4.4.3.CJSON工具类 OpenResty提供了一个cjson的模块用来处理JSON的序列化和反序列化。 官方地址&#xff1a; https://github.com/openresty/lua-cjson/ 1&#xff09;引入cjson模块&#xff1a; local cjson require "cjson"2&#xff09;序列化&#xff1a; …

记录海豚调度器删除工作流实例失败的解决办法(DolphinScheduler的WebUI删除失败)

本博客记录以下问题解决办法&#xff1a;使用dolphinscheduler的WebUI运行工作流后出现内存占用过高导致的任务阻塞问题&#xff0c;并且在删除工作流实例时总是报错无法删除 解决步骤 在前端页面无法删除&#xff0c;于是搜索资料&#xff0c;发现可以登录数据库进行工作流实…

Day05-docker-compose与私有仓库

Day05-docker-compose与私有仓库 3.4 Docker Compose1&#xff09;compose极速上手指南案例28-初步上手docker-compose2&#xff09;compose文件的常用指令3&#xff09;案例29-docker-compose部署kodexp5&#xff09;小结 3.5 docker镜像仓库之registry仓库1&#xff09;仓库选…

Qt中常用对话框

Qt中的对话框&#xff08;QDialog&#xff09;是用户交互的重要组件&#xff0c;用于向用户提供特定的信息、请求输入、或进行决策。Qt提供了多种标准对话框以及用于自定义对话框的类。以下将详细介绍几种常用对话框的基本使用、使用技巧以及注意事项&#xff0c;并附带C示例代…

SV-7041T IP网络有源音箱 教室广播多媒体音箱(带本地扩音功能)教学广播音箱 办公室背景音乐广播音箱 2.0声道壁挂式网络有源音箱

SV-7041T IP网络有源音箱 教室广播多媒体音箱&#xff08;带本地扩音功能&#xff09; 教学广播音箱 办公室背景音乐广播音箱 一、描述 SV-7041T是深圳锐科达电子有限公司的一款2.0声道壁挂式网络有源音箱&#xff0c;具有10/100M以太网接口&#xff0c;可将网络音源通过自带…

学习指导|在改变

备忘在这里啦。潦草本草

黑马微服务课程2

课程地址&#xff1a;2024最新SpringCloud微服务开发与实战&#xff0c;java黑马商城项目微服务实战开发&#xff08;涵盖MybatisPlus、Docker、MQ、ES、Redis高级等&#xff09;_哔哩哔哩_bilibili 课程名称&#xff1a;2024最新SpringCloud微服务开发与实战&#xff0c;java…

【1429】招生管理管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java 招生管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0&…

android脱壳:一种使用native进行抽取壳脱壳的方法,native版本的frida-fart

前言 写rxposed的时候&#xff0c;搞了很多模块&#xff0c;其中有一个远程调用脱壳的&#xff0c;但是当时使用的是rmi远程调用&#xff0c;因为一些问题无法使用&#xff0c;可能是对抗问题&#xff0c;也有可能是技术问题&#xff0c;所以我又换了一种远程调用方式。 概述…

21-22 - 线性表的链式存储结构 单链表的具体实现

---- 整理自狄泰软件唐佐林老师课程 文章目录 1. 线性表的链式存储结构1.1 定义1.2 逻辑结构1.3 专业术语的统一 2. 链表的基本概念2.1 单链表中的结点定义2.2 单链表中的内部结构2.3 在目标位置处插入数据元素2.4 在目标位置处删除数据元素 3. 链式存储结构线性表的实现3.1 设…

排列对称串

Description:很多字串&#xff0c;有些是对称的&#xff0c;有些是不对称的&#xff0c;请将那些对称的字事按从小到大的顺序输出&#xff0c;字事先以长度论大小&#xff0c;如果长度相同&#xff0c;再以ASCI码值为大小标准 Input.输入数据中含有一些字串(1≤串长≤256)。 #…

linux文件句柄数满,linux文件句柄数超出系统限制怎么办?

1、问题阐述&#xff1a; too many open files&#xff1a;顾名思义即打开过多文件数。 不过这里的files不单是文件的意思&#xff0c;也包括打开的通讯链接(比如socket)&#xff0c;正在监听的端口等等&#xff0c;所以有时候也可以叫做句柄(handle)&#xff0c;这个错误通常…

Rust腐蚀服务器搭建架设教程ubuntu系统

Rust腐蚀服务器搭建架设教程ubuntu系统 大家好我是艾西一个做服务器租用的网络架构师。Rust腐蚀游戏对于服务器的配置有一定的要求很多小伙伴就思考用linux系统搭建的话占用会不会小一点&#xff0c;有一定电脑基础的小伙伴都知道Linux系统和windows系统相比较linux因为是面板…

coreldraw2024精简版绿色版安装包免费下载

CorelDRAW 2024是一款矢量图形设计软件&#xff0c;于2024年3月5日正式在全球范围内发布。这款软件在多个方面进行了更新和改进&#xff0c;为用户提供了更多高效、灵活和便捷的设计工具。 首先&#xff0c;CorelDRAW 2024新增了绘画笔刷功能&#xff0c;这些笔刷不仅模拟了传…

算法学习001-圆桌问题 中小学算法思维学习 信奥算法解析 c++实现

目录 算法学习001-圆桌问题 一、题目要求 1、编程实现 2、输入输出 二、算法分析 三、程序编写 四、程序说明 五、运行结果 六、考点分析 七、推荐资料 算法学习001-圆桌问题 一、题目要求 1、编程实现 圆桌边围坐着2n个人&#xff0c;其中n个人是好人&#xff0c…

【199.二叉树的右视图】_二叉树_day01

1 题目描述 给定一个二叉树的 根节点 root&#xff0c;想象自己站在它的右侧&#xff0c;按照从顶部到底部的顺序&#xff0c;返回从右侧所能看到的节点值。199.二叉树的右视图 2 解题思路 此题是二叉树层序遍历的拓展。 创建一个队列que (Queue)起到中介的作用&#xff0c…

Atom-7B-Chat本地推理

Atom-7B-Chat 本地推理 基础环境信息&#xff08;wsl2安装Ubuntu22.04 miniconda&#xff09; 使用miniconda搭建环境 (base) :~$ conda create --name Llama-Chinese python3.10 Retrieving notices: ...working... done Channels:- defaults Platform: linux-64 Collectin…

RealSenseSR300工程环境配置说明

新建目录结构如下&#xff1a; output:存储可执行文件.exe等src:存储源码.cpp .h等3rdparty:存储第三方库 opencv等 其中将源码按照main及其相关文件分为以下三类 vs2015许可证到期后先激活&#xff0c;激活码很多网上有&#xff0c;如&#xff1a;HMGNV-WCYXV-X7G9W-YCX63…

企业微信hook接口协议,根据手机号搜索联系人

根据手机号搜索联系人 参数名必选类型说明uuid是String每个实例的唯一标识&#xff0c;根据uuid操作具体企业微信 请求示例 {"uuid":"3240fde0-45e2-48c0-90e8-cb098d0ebe43","phoneNumber":"1357xxxx" } 返回示例 {"data&q…

【SQL代理中转注入】对DVWA登录界面username字段实施注入

一、实验过程 步骤0&#xff1a;注释掉相关username防护&#xff0c;截图如下&#xff1a; 以DVWA为攻击目标&#xff0c;将login.php中第21、22行注释掉 步骤1&#xff1a;源码分析&#xff0c;截图如下&#xff1a; 如此可知&#xff0c;首先需要通过token验证&#xff0c;然…
最新文章