React admin 如何使用简单列表启用批量操作

React admin 如何使用简单列表启用批量操作,react-admin,React Admin,我需要为列表创建一个不同的视图,以便可以在移动设备上查看它。有人建议我使用SimpleList,但我仍然希望用户能够选择列表中的多个项目并完成批量操作。有办法做到这一点吗?React Admin文档中没有太多关于此场景的文档。我没有足够的声誉来投票支持此方案,但是,使用当前的SimpleList,我制作了一个可供选择的(批量操作)版本,可用于我的目的 它也可能对你有用 它是在常规的JS中,而不是像原版那样的TypeScript 要使用它,只需导入文件,如: import SelectSimple

我需要为列表创建一个不同的视图,以便可以在移动设备上查看它。有人建议我使用SimpleList,但我仍然希望用户能够选择列表中的多个项目并完成批量操作。有办法做到这一点吗?React Admin文档中没有太多关于此场景的文档。

我没有足够的声誉来投票支持此方案,但是,使用当前的SimpleList,我制作了一个可供选择的(批量操作)版本,可用于我的目的

它也可能对你有用

它是在常规的JS中,而不是像原版那样的TypeScript

要使用它,只需导入文件,如:

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)}>
            &nbsp;
        </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>&nbsp;</Avatar>
                        </ListItemAvatar>
                    )}
                    <ListItemText
                        primary={
                            <div>
                                <Placeholder className={classes.primary} />
                                {hasTertiaryText && (
                                    <span className={classes.tertiary}>
                                        <Placeholder />
                                    </span>
                                )}
                            </div>
                        }
                        secondary={
                            hasSecondaryText ? <Placeholder /> : undefined
                        }
                    />
                    {hasRightAvatarOrIcon && (
                        <ListItemSecondaryAction>
                            <Avatar>&nbsp;</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&&(