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

2024-04-25 07:28

本文主要是介绍【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><TransferdataSource={mockData} // 数据源,即需要在两个列表之间移动的数据列表titles={['Source', 'Target']} // 列表的标题,包括源列表和目标列表的标题targetKeys={targetKeys} // 目标列表中的键数组,表示当前已经选中的项的键数组selectedKeys={selectedKeys} // 当前选中的项的键数组,用于在两个列表之间移动项时的状态管理onChange={onChange} // 当目标列表中的键数组改变时触发的事件回调函数onSelectChange={onSelectChange} // 当源列表和目标列表中的选中项改变时触发的事件回调函数onScroll={onScroll} // 当滚动时触发的事件回调函数onSearch={handleSearch} // 当搜索框中的值改变时触发的事件回调函数render={item => item.title} // 定义如何渲染每个数据项,返回一个React元素oneWay // 是否只允许从左侧列表向右侧列表移动数据,默认为falseshowSearch // 是否显示搜索框,默认为falsepagination // 是否显示分页,默认为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 (<TablerowSelection={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 => (<Tagstyle={{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} // 右侧表格列配置/><Spacestyle={{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))}// 父节点如果被选中,则添加所有子节点到 checkedKeysif (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)}// 如果没有找到父节点,则直接返回 updatedKeysreturn 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 (<TreeblockNodecheckablecheckStrictlydefaultExpandAllcheckedKeys={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

在这里插入图片描述

这篇关于【Ant-Desgin-React 穿梭框】表格穿梭框,树穿梭框的用法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


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

相关文章

Java Spring的依赖注入理解及@Autowired用法示例详解

《JavaSpring的依赖注入理解及@Autowired用法示例详解》文章介绍了Spring依赖注入(DI)的概念、三种实现方式(构造器、Setter、字段注入),区分了@Autowired(注入... 目录一、什么是依赖注入(DI)?1. 定义2. 举个例子二、依赖注入的几种方式1. 构造器注入(Con

详解MySQL中JSON数据类型用法及与传统JSON字符串对比

《详解MySQL中JSON数据类型用法及与传统JSON字符串对比》MySQL从5.7版本开始引入了JSON数据类型,专门用于存储JSON格式的数据,本文将为大家简单介绍一下MySQL中JSON数据类型... 目录前言基本用法jsON数据类型 vs 传统JSON字符串1. 存储方式2. 查询方式对比3. 索引

从入门到精通详解LangChain加载HTML内容的全攻略

《从入门到精通详解LangChain加载HTML内容的全攻略》这篇文章主要为大家详细介绍了如何用LangChain优雅地处理HTML内容,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录引言:当大语言模型遇见html一、HTML加载器为什么需要专门的HTML加载器核心加载器对比表二

全面掌握 SQL 中的 DATEDIFF函数及用法最佳实践

《全面掌握SQL中的DATEDIFF函数及用法最佳实践》本文解析DATEDIFF在不同数据库中的差异,强调其边界计算原理,探讨应用场景及陷阱,推荐根据需求选择TIMESTAMPDIFF或inte... 目录1. 核心概念:DATEDIFF 究竟在计算什么?2. 主流数据库中的 DATEDIFF 实现2.1

MySQL中的LENGTH()函数用法详解与实例分析

《MySQL中的LENGTH()函数用法详解与实例分析》MySQLLENGTH()函数用于计算字符串的字节长度,区别于CHAR_LENGTH()的字符长度,适用于多字节字符集(如UTF-8)的数据验证... 目录1. LENGTH()函数的基本语法2. LENGTH()函数的返回值2.1 示例1:计算字符串

Java中的数组与集合基本用法详解

《Java中的数组与集合基本用法详解》本文介绍了Java数组和集合框架的基础知识,数组部分涵盖了一维、二维及多维数组的声明、初始化、访问与遍历方法,以及Arrays类的常用操作,对Java数组与集合相... 目录一、Java数组基础1.1 数组结构概述1.2 一维数组1.2.1 声明与初始化1.2.2 访问

MySQL 中的 CAST 函数详解及常见用法

《MySQL中的CAST函数详解及常见用法》CAST函数是MySQL中用于数据类型转换的重要函数,它允许你将一个值从一种数据类型转换为另一种数据类型,本文给大家介绍MySQL中的CAST... 目录mysql 中的 CAST 函数详解一、基本语法二、支持的数据类型三、常见用法示例1. 字符串转数字2. 数字

Python中你不知道的gzip高级用法分享

《Python中你不知道的gzip高级用法分享》在当今大数据时代,数据存储和传输成本已成为每个开发者必须考虑的问题,Python内置的gzip模块提供了一种简单高效的解决方案,下面小编就来和大家详细讲... 目录前言:为什么数据压缩如此重要1. gzip 模块基础介绍2. 基本压缩与解压缩操作2.1 压缩文

解读GC日志中的各项指标用法

《解读GC日志中的各项指标用法》:本文主要介绍GC日志中的各项指标用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、基础 GC 日志格式(以 G1 为例)1. Minor GC 日志2. Full GC 日志二、关键指标解析1. GC 类型与触发原因2. 堆

MySQL数据库中ENUM的用法是什么详解

《MySQL数据库中ENUM的用法是什么详解》ENUM是一个字符串对象,用于指定一组预定义的值,并可在创建表时使用,下面:本文主要介绍MySQL数据库中ENUM的用法是什么的相关资料,文中通过代码... 目录mysql 中 ENUM 的用法一、ENUM 的定义与语法二、ENUM 的特点三、ENUM 的用法1