React admin 如何使用简单列表启用批量操作
我需要为列表创建一个不同的视图,以便可以在移动设备上查看它。有人建议我使用SimpleList,但我仍然希望用户能够选择列表中的多个项目并完成批量操作。有办法做到这一点吗?React Admin文档中没有太多关于此场景的文档。我没有足够的声誉来投票支持此方案,但是,使用当前的SimpleList,我制作了一个可供选择的(批量操作)版本,可用于我的目的 它也可能对你有用 它是在常规的JS中,而不是像原版那样的TypeScript 要使用它,只需导入文件,如:React admin 如何使用简单列表启用批量操作,react-admin,React Admin,我需要为列表创建一个不同的视图,以便可以在移动设备上查看它。有人建议我使用SimpleList,但我仍然希望用户能够选择列表中的多个项目并完成批量操作。有办法做到这一点吗?React Admin文档中没有太多关于此场景的文档。我没有足够的声誉来投票支持此方案,但是,使用当前的SimpleList,我制作了一个可供选择的(批量操作)版本,可用于我的目的 它也可能对你有用 它是在常规的JS中,而不是像原版那样的TypeScript 要使用它,只需导入文件,如: import SelectSimple
import SelectSimpleList from './SelectSimpleList'
并以与原始SimpleList完全相同的方式使用它
选择SimpleList.js:
import * as React from 'react';
import PropTypes from 'prop-types';
import {
Avatar,
List,
//ListProps,
ListItem,
ListItemAvatar,
ListItemIcon,
ListItemSecondaryAction,
ListItemText,
} from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import { Link } from 'react-router-dom';
import {
linkToRecord,
sanitizeListRestProps,
useListContext,
//Record,
//RecordMap,
//Identifier,
} from 'ra-core';
import Checkbox from '@material-ui/core/Checkbox';
import { useTimeout } from 'ra-core';
import classnames from 'classnames';
const useStylesPlaceholder = makeStyles(
theme => ({
root: {
backgroundColor: theme.palette.grey[300],
display: 'flex',
},
}),
{ name: 'RaPlaceholder' }
);
const Placeholder = props => {
const classes = useStylesPlaceholder(props);
return (
<span className={classnames(classes.root, props.className)}>
</span>
);
};
const useStylesLoading = makeStyles(
theme => ({
primary: {
width: '30vw',
display: 'inline-block',
marginBottom: theme.spacing(),
},
tertiary: { float: 'right', opacity: 0.541176, minWidth: '10vw' },
}),
{ name: 'RaSimpleListLoading' },
);
const times = (nbChildren, fn) =>
Array.from({ length: nbChildren }, (_, key) => fn(key));
const SimpleListLoading = props => {
const {
classes: classesOverride,
className,
hasLeftAvatarOrIcon,
hasRightAvatarOrIcon,
hasSecondaryText,
hasTertiaryText,
nbFakeLines = 5,
...rest
} = props;
const classes = useStylesLoading(props);
const oneSecondHasPassed = useTimeout(1000);
return oneSecondHasPassed ? (
<List className={className} {...rest}>
{times(nbFakeLines, key => (
<ListItem key={key}>
{hasLeftAvatarOrIcon && (
<ListItemAvatar>
<Avatar> </Avatar>
</ListItemAvatar>
)}
<ListItemText
primary={
<div>
<Placeholder className={classes.primary} />
{hasTertiaryText && (
<span className={classes.tertiary}>
<Placeholder />
</span>
)}
</div>
}
secondary={
hasSecondaryText ? <Placeholder /> : undefined
}
/>
{hasRightAvatarOrIcon && (
<ListItemSecondaryAction>
<Avatar> </Avatar>
</ListItemSecondaryAction>
)}
</ListItem>
))}
</List>
) : null;
};
SimpleListLoading.propTypes = {
className: PropTypes.string,
hasLeftAvatarOrIcon: PropTypes.bool,
hasRightAvatarOrIcon: PropTypes.bool,
hasSecondaryText: PropTypes.bool,
hasTertiaryText: PropTypes.bool,
nbFakeLines: PropTypes.number,
};
const useStyles = makeStyles(
{
tertiary: { float: 'right', opacity: 0.541176 },
},
{ name: 'RaSimpleList' }
);
/**
* The <SimpleList> component renders a list of records as a material-ui <List>.
* It is usually used as a child of react-admin's <List> and <ReferenceManyField> components.
*
* Also widely used on Mobile.
*
* Props:
* - primaryText: function returning a React element (or some text) based on the record
* - secondaryText: same
* - tertiaryText: same
* - leftAvatar: function returning a React element based on the record
* - leftIcon: same
* - rightAvatar: same
* - rightIcon: same
* - linkType: 'edit' or 'show', or a function returning 'edit' or 'show' based on the record
* - rowStyle: function returning a style object based on (record, index)
*
* @example // Display all posts as a List
* const postRowStyle = (record, index) => ({
* backgroundColor: record.views >= 500 ? '#efe' : 'white',
* });
* export const PostList = (props) => (
* <List {...props}>
* <SimpleList
* primaryText={record => record.title}
* secondaryText={record => `${record.views} views`}
* tertiaryText={record =>
* new Date(record.published_at).toLocaleDateString()
* }
* rowStyle={postRowStyle}
* />
* </List>
* );
*/
const SelectSimpleList = props => {
const {
className,
classes: classesOverride,
hasBulkActions,
leftAvatar,
leftIcon,
linkType = 'edit',
primaryText,
rightAvatar,
rightIcon,
secondaryText,
tertiaryText,
rowStyle,
...rest
} = props;
const { basePath, data, ids, loaded, total, onToggleItem, selectedIds } = useListContext(props);
const classes = useStyles(props);
if (loaded === false) {
return (
<SimpleListLoading
classes={classes}
className={className}
hasLeftAvatarOrIcon={!!leftIcon || !!leftAvatar}
hasRightAvatarOrIcon={!!rightIcon || !!rightAvatar}
hasSecondaryText={!!secondaryText}
hasTertiaryText={!!tertiaryText}
/>
);
}
const isSelected = id => {
if (selectedIds.includes(id)){
return true;
}
return false;
}
return (
total > 0 && (
<List className={className} {...sanitizeListRestProps(rest)}>
{ids.map((id, rowIndex) => (
<LinkOrNot
linkType={linkType}
basePath={basePath}
id={id}
key={id}
record={data[id]}
>
<ListItem
//onClick={() => {onToggleItem(id)}}
button={!!linkType}
style={
rowStyle
? rowStyle(data[id], rowIndex)
: undefined
}
>
<Checkbox
checked={isSelected(id)}
onChange={() => onToggleItem(id)}
color="primary"
onClick={(e) => e.stopPropagation()}
inputProps={{ 'aria-label': 'primary checkbox' }}
/>
{leftIcon && (
<ListItemIcon>
{leftIcon(data[id], id)}
</ListItemIcon>
)}
{leftAvatar && (
<ListItemAvatar>
<Avatar>{leftAvatar(data[id], id)}</Avatar>
</ListItemAvatar>
)}
<ListItemText
primary={
<div>
{primaryText(data[id], id)}
{tertiaryText && (
<span className={classes.tertiary}>
{tertiaryText(data[id], id)}
</span>
)}
</div>
}
secondary={
secondaryText && secondaryText(data[id], id)
}
/>
{(rightAvatar || rightIcon) && (
<ListItemSecondaryAction>
{rightAvatar && (
<Avatar>
{rightAvatar(data[id], id)}
</Avatar>
)}
{rightIcon && (
<ListItemIcon>
{rightIcon(data[id], id)}
</ListItemIcon>
)}
</ListItemSecondaryAction>
)}
</ListItem>
</LinkOrNot>
))}
</List>
)
);
};
SelectSimpleList.propTypes = {
className: PropTypes.string,
classes: PropTypes.object,
leftAvatar: PropTypes.func,
leftIcon: PropTypes.func,
linkType: PropTypes.oneOfType([
PropTypes.string,
PropTypes.bool,
PropTypes.func,
]),
primaryText: PropTypes.func,
rightAvatar: PropTypes.func,
rightIcon: PropTypes.func,
secondaryText: PropTypes.func,
tertiaryText: PropTypes.func,
rowStyle: PropTypes.func,
};
const useLinkOrNotStyles = makeStyles(
{
link: {
textDecoration: 'none',
color: 'inherit',
},
},
{ name: 'RaLinkOrNot' }
);
const LinkOrNot = ({
classes: classesOverride,
linkType,
basePath,
id,
children,
record,
}) => {
const classes = useLinkOrNotStyles({ classes: classesOverride });
const link =
typeof linkType === 'function' ? linkType(record, id) : linkType;
return link === 'edit' || link === true ? (
<Link to={linkToRecord(basePath, id)} className={classes.link}>
{children}
</Link>
) : link === 'show' ? (
<Link
to={`${linkToRecord(basePath, id)}/show`}
className={classes.link}
>
{children}
</Link>
) : (
<span>{children}</span>
);
};
export default SelectSimpleList;
import*as React from'React';
从“道具类型”导入道具类型;
进口{
阿凡达
列表
//列表道具,
列表项,
ListItemAvatar,
ListItemIcon,
ListItemSecondaryAction,
ListItemText,
}来自“@material ui/core”;
从'@material ui/core/styles'导入{makeStyles};
从'react router dom'导入{Link};
进口{
链接记录,
消毒剂,
useListContext,
//记录,
//记录地图,
//标识符,
}来自“ra核心”;
从“@material ui/core/Checkbox”导入复选框;
从'ra core'导入{useTimeout};
从“类名称”导入类名称;
const useStylesPlaceholder=makeStyles(
主题=>({
根目录:{
背景色:主题。调色板。灰色[300],
显示:“flex”,
},
}),
{name:'RaPlaceholder'}
);
常量占位符=道具=>{
常量类=useStylesPlaceholder(道具);
返回(
);
};
const useStylesLoading=makeStyles(
主题=>({
主要:{
宽度:“30vw”,
显示:“内联块”,
marginBottom:theme.spacing(),
},
三级:{float:'right',不透明度:0.541176,minWidth:'10vw'},
}),
{name:'RaSimpleListLoading'},
);
常量时间=(nbChildren,fn)=>
数组.from({length:nbChildren},({u0,key)=>fn(key));
const SimpleListLoading=props=>{
常数{
类别:classesOverride,
类名,
他是个左撇子,
哈斯维特罗克,
Hassencondarytext,
催促文本,
nbfakeline=5,
休息
}=道具;
常量类=使用样式加载(道具);
const oneSecondHasPassed=useTimeout(1000);
返回一秒已过(
{次(nbfakeline,key=>(
{hasleeftavataroricon&&(
)}
{hasRightAvatarOrIcon&&(
)}
))}
):null;
};
SimpleListLoading.propTypes={
类名:PropTypes.string,
hasLeftAvatarOrIcon:PropTypes.bool,
hasRightAvatarOrIcon:PropTypes.bool,
HassSecondaryText:PropTypes.bool,
HasterTypes.bool,
nbFakeLines:PropTypes.number,
};
const useStyles=makeStyles(
{
三级:{float:'right',不透明度:0.541176},
},
{name:'RaSimpleList'}
);
/**
*该组件将记录列表呈现为材质ui。
*它通常用作react管理员和组件的子级。
*
*也广泛应用于手机上。
*
*道具:
*-primaryText:基于记录返回React元素(或某些文本)的函数
*-第二个文本:相同
*-第三段文字:相同
*-leftAvatar:基于记录返回React元素的函数
*-左图标:相同
*-右阿凡达:相同
*-右图标:相同
*-linkType:“编辑”或“显示”,或基于记录返回“编辑”或“显示”的函数
*-rowStyle:基于(记录、索引)返回样式对象的函数
*
*@example//将所有帖子显示为列表
*const postRowStyle=(记录、索引)=>({
*背景颜色:record.views>=500?#efe:“白色”,
* });
*导出常量PostList=(道具)=>(
*
*记录.标题}
*secondaryText={record=>`${record.views}views`}
*tertiaryText={record=>
*新日期(record.published_at).toLocaleDateString()
* }
*rowStyle={postRowStyle}
* />
*
* );
*/
const SelectSimpleList=props=>{
常数{
类名,
类别:classesOverride,
他说,,
左阿凡达,
左图标,
链接类型='编辑',
primaryText,
对,阿凡达,,
右图标,
第二文本,
三段文字,
赛艇风格,
休息
}=道具;
const{basePath,data,ids,loaded,total,ontogleItem,selectedIds}=useListContext(props);
常量类=使用样式(道具);
如果(已加载===false){
返回(
);
}
const isSelected=id=>{
如果(已选择id.includes(id)){
返回true;
}
返回false;
}
返回(
总计>0&&(
{ids.map((id,rowIndex)=>(
{onToggleItem(id)}
按钮={!!链接类型}
风格={
赛艇风格
?行样式(数据[id],行索引)
:未定义
}
>
onToggleItem(id)}
color=“primary”
onClick={(e)=>e.stopPropagation()}
inputProps={{“aria标签”:“主复选框”}
/>
{leftIcon&&(