List视图

列表视图显示从REST API提取的记录列表。此视图的入口点是<List>组件,它负责获取数据。然后,它将数据传递到迭代器视图-通常是<Datagrid>,然后将每个记录属性的渲染委托给<Field>组件。

The List View

<List> 组件

<List>组件渲染列表布局(标题、按钮、筛选器、分页),并从 REST API 中提取记录列表。然后将记录列表的呈现委托给其子组件。通常,它是一个<Datagrid>,负责显示一个具有每个帖子一行的表格。

提示:在Redux条款中,<List>是一个connected组件,并且<Datagrid>是一个dumb组件。

以下是通过<List>组件接受的所有属性:

下面是显示帖子列表所需的最少代码:

// in src/App.js
import React from 'react';
import { jsonServerRestClient, Admin, Resource } from 'admin-on-rest';

import { PostList } from './posts';

const App = () => (
    <Admin restClient={jsonServerRestClient('http://jsonplaceholder.typicode.com')}>
        <Resource name="posts" list={PostList} />
    </Admin>
);

export default App;

// in src/posts.js
import React from 'react';
import { List, Datagrid, TextField } from 'admin-on-rest';

export const PostList = (props) => (
    <List {...props}>
        <Datagrid>
            <TextField source="id" />
            <TextField source="title" />
            <TextField source="body" />
        </Datagrid>
    </List>
);

这足以显示帖子列表:

Simple posts list

title(页面标题)

一个列表视图的默认标题是"[resource] list"(例如:"Posts list")。使用title属性来自定义列表视图标题:

// in src/posts.js
export const PostList = (props) => (
    <List {...props} title="List of posts">
        ...
    </List>
);

标题可以是任何一个字符串,或者你自己的元素。

actions(动作)

你可以通过你自己的元素使用actions属性替换掉默认的action列表:

import { CardActions } from 'material-ui/Card';
import FlatButton from 'material-ui/FlatButton';
import NavigationRefresh from 'material-ui/svg-icons/navigation/refresh';
import CreateButton from '../button/CreateButton';

const cardActionStyle = {
    zIndex: 2,
    display: 'inline-block',
    float: 'right',
};

const PostActions = ({ resource, filters, displayedFilters, filterValues, basePath, showFilter, refresh }) => (
    <CardActions style={cardActionStyle}>
        {filters && React.cloneElement(filters, { resource, showFilter, displayedFilters, filterValues, context: 'button' }) }
        <CreateButton basePath={basePath} />
        <FlatButton primary label="refresh" onClick={refresh} icon={<NavigationRefresh />} />
        {/* Add your custom actions */}
        <FlatButton primary label="Custom Action" onClick={customAction} />
    </CardActions>
);

export const PostList = (props) => (
    <List {...props} actions={<PostActions />}>
        ...
    </List>
);

filters(过滤器)

你可以使用filters属性添加一个过滤器元素到这个列表:

const PostFilter = (props) => (
    <Filter {...props}>
        <TextInput label="Search" source="q" alwaysOn />
        <TextInput label="Title" source="title" defaultValue="Hello, World!" />
    </Filter>
);

export const PostList = (props) => (
    <List {...props} filters={<PostFilter />}>
        ...
    </List>
);

过滤器组件必须是一个具有<Input>子级的<Filter>组件。

提示<Filter>是一个特殊的组件,它以两种方式呈现:

  • 作为一个过滤器按钮(去添加新过滤器)
  • 作为过滤器表单(去输入过滤器值)

它通过检查它的context属性这样做的。

提示:不要混淆这个 filters 属性,期望一个React 元素,具有 filter 属性,它期望一个对象来定义永久过滤器 (见下文)。

perPage(每页记录数)

默认情况下,列表为10个一组的结果标记页码。你可以通过指定perPage属性覆写这个设置:

// in src/posts.js
export const PostList = (props) => (
    <List {...props} perPage={25}>
        ...
    </List>
);

sort(默认排序字段)

传递一个对象字面量作为sort属性来确定用于排序的fieldorder

// in src/posts.js
export const PostList = (props) => (
    <List {...props} sort={{ field: 'published_at', order: 'DESC' }}>
        ...
    </List>
);

sort定义了default排序顺序;这个列表通过在列标题上单击保持可排序。

禁用排序

通过传递一个设置为falsesortable属性,它可能会为一个指定的字段去禁用排序:

// in src/posts.js
import React from 'react';
import { List, Datagrid, TextField } from 'admin-on-rest/lib/mui';

export const PostList = (props) => (
    <List {...props}>
        <Datagrid>
            <TextField source="id" sortable={false} />
            <TextField source="title" />
            <TextField source="body" />
        </Datagrid>
    </List>
);

filter(永久过滤器)

您可以选择始终过滤列表,而不允许用户禁用此过滤器,例如只显示已发布的帖子。在filter属性中写被传递到REST客户端的过滤器:

// in src/posts.js
export const PostList = (props) => (
    <List {...props} filter={{ is_published: true }}>
        ...
    </List>
);

发送到REST客户端的实际过滤器参数是user过滤器(通过filters组件表单设置的)和permanent过滤器组合的结果。用户不能通过filter的方式来重写设置的永久筛选器。

pagination(分页)

你可以通过你自己分页元素来替换默认分页元素,使用pagination属性。分页元素接收当前页、每页的记录数、记录总数以及更改页面的setPage()函数。

因此,如果您想要通过一个""分页来替换默认的分页。创建如下所示的页状组件:

import FlatButton from 'material-ui/FlatButton';
import ChevronLeft from 'material-ui/svg-icons/navigation/chevron-left';
import ChevronRight from 'material-ui/svg-icons/navigation/chevron-right';
import { Toolbar, ToolbarGroup } from 'material-ui/Toolbar';

const PostPagination = ({ page, perPage, total, setPage }) => {
    const nbPages = Math.ceil(total / perPage) || 1;
    return (
        nbPages > 1 &&
            <Toolbar>
                <ToolbarGroup>
                {page > 1 &&
                    <FlatButton primary key="prev" label="Prev" icon={<ChevronLeft />} onClick={() => setPage(page - 1)} />
                }
                {page !== nbPages &&
                    <FlatButton primary key="next" label="Next" icon={<ChevronRight />} onClick={() => setPage(page + 1)} labelPosition="before" />
                }
                </ToolbarGroup>
            </Toolbar>
    );
}

export const PostList = (props) => (
    <List {...props} pagination={<PostPagination />}>
        ...
    </List>
);

<Datagrid>组件

datagrid组件渲染纪录列表作为一个表格。它通常被用作<List><ReferenceManyField>组件的子级。

以下是通过这个组件接受的所有属性:

它渲染的列数与接收的<Field>子级相同。

// in src/posts.js
import React from 'react';
import { List, Datagrid, TextField } from 'admin-on-rest';

export const PostList = (props) => (
    <List {...props}>
        <Datagrid>
            <TextField source="id" />
            <TextField source="title" />
            <TextField source="body" />
            <EditButton />
        </Datagrid>
    </List>
);

datagrid是一个迭代器组件:它接收一个ids数组,和一个数据store,并且应该遍历ids以显示每个记录。迭代器组件的另一个例子是<SingleFieldList>

自定义表格样式

你可以通过一个styles对象作为属性自定义datagrid样式。该对象应具有以下属性:

const datagridStyles = {
    table: { },
    tbody: { },
    tr: { },
    header: {
        th: { },
        'th:first-child': { }, // special style for the first header column
    },
    cell: {
        td: { },
        'td:first-child': { }, // special style for the first column
    },
};

export const PostList = (props) => (
    <List {...props}>
        <Datagrid styles={datagridStyles}>
            ...
        </Datagrid>
    </List>
);

提示:如果你想要为每列独立地重写headercell,在<Field>组件中使用headerStylestyle属性:

export const PostList = (props) => (
    <List {...props}>
        <Datagrid>
            <TextField source="id" />
            <TextField source="title" />
            <TextField
                source="views"
                style={{ textAlign: 'right' }}
                headerStyle={{ textAlign: 'right' }}
            />
        </Datagrid>
    </List>
);

提示:如果您想更进一步,并按单元格应用一个自定义样式单元格,请查看主题章节的条件格式部分

行样式函数

你可以基于记录自定义datagrid行样式(适用于<tr>元素),感谢rowStyle属性,它期望是一个函数。

例如,如果记录的一个值 - 如其视图的数量 - 通过某个阈值,则允许对整个行应用自定义背景。

const postRowStyle = (record, index) => ({
    backgroundColor: record.nb_views >= 500 ? '#efe' : 'white',
});
export const PostList = (props) => (
    <List {...props}>
        <Datagrid rowStyle={postRowStyle}>
            ...
        </Datagrid>
    </List>
);

optionsheaderOptionsbodyOptionsrowOptions

Admin-on-rest依赖material-ui的<Table>组件用于呈现datagrid。optionsheaderOptionsbodyOptionsrowOptions属性允许你去重写<Table><TableHeader><TableBody><TableRow>的属性。

例如,若要获得表上的一个固定的标头,重写<Table>属性用options

export const PostList = (props) => (
    <List {...props}>
        <Datagrid options={{ fixedHeader: true, height: 400 }}>
            ...
        </Datagrid>
    </List>
);

若要启用条纹的行和行悬停,重写<TableBody>属性用bodyOptions

export const PostList = (props) => (
    <List {...props}>
        <Datagrid bodyOptions={{ stripedRows: true, showRowHover: true }}>
            ...
        </Datagrid>
    </List>
);

有关你可以通过这些选项覆盖所有可用的属性列表,请参阅material-ui<Table>组件文档

<SimpleList>组件

对于移动设备,<Datagrid>通常是不可用的-仅仅没有足够的空间来显示多列。在这种情况下,约定是使用简单列表,它具有每行只有一列。<SimpleList>组件为这个目的服务,利用material-ui的<List><ListItem>组件。你可以使用它作为<List>或者<ReferenceManyField>子级:

// in src/posts.js
import React from 'react';
import { List, SimpleList } from 'admin-on-rest';

export const PostList = (props) => (
    <List {...props}>
        <SimpleList
            primaryText={record => record.title}
            secondaryText={record => `${record.views} views`}
            tertiaryText={record => new Date(record.published_at).toLocaleDateString()}
        />
    </List>
);

<SimpleList>遍历列表数据。对于每个记录,它执行primaryText、secondaryText、 leftAvatar、leftIcon、rightAvatar和rightIcon的属性函数,并传递结果作为相应的属性。

提示:在小屏幕上使用一个<SimpleList>并在较大的屏幕上使用一个<Datagrid>,使用<Responsive>组件:

// in src/posts.js
import React from 'react';
import { List, Responsive, SimpleList, Datagrid, TextField, ReferenceField, EditButton } from 'admin-on-rest';

export const PostList = (props) => (
    <List {...props}>
        <Responsive
            small={
                <SimpleList
                    primaryText={record => record.title}
                    secondaryText={record => `${record.views} views`}
                    tertiaryText={record => new Date(record.published_at).toLocaleDateString()}
                />
            }
            medium={
                <Datagrid>
                    ...
                </Datagrid>
            }
        />
    </List>
);

<SingleFieldList>组件

当你想要只显示记录列表的一个属性,而不是使用<Datagrid>,请使用<SingleFieldList>。它期望单个<Field>作为子级。它特别适用于<ReferenceManyField>组件:

// Display all the books by the current author
<ReferenceManyField reference="books" target="author_id">
    <SingleFieldList>
        <ChipField source="title" />
    </SingleFieldList>
</ReferenceManyField>

ReferenceManyFieldSingleFieldList

使用一个自定义迭代器

一个<List>能委托到任何迭代器组件 - <Datagrid>仅仅是一个例子。一个迭代器组件必须接受至少两个属性:

  • ids是当前显示在列表中的id的数组。
  • data是一个用于此resource的所有取来数据的对象,通过id索引。

例如,如果您希望显示卡片列表而不是datagrid,该怎么办?

Custom iterator

很简单: 创建您自己的迭代器组件,如下所示:

// in src/comments.js
const cardStyle = {
    width: 300,
    minHeight: 300,
    margin: '0.5em',
    display: 'inline-block',
    verticalAlign: 'top'
};
const CommentGrid = ({ ids, data, basePath }) => (
    <div style={{ margin: '1em' }}>
    {ids.map(id =>
        <Card key={id} style={cardStyle}>
            <CardHeader
                title={<TextField record={data[id]} source="author.name" />}
                subtitle={<DateField record={data[id]} source="created_at" />}
                avatar={<Avatar icon={<PersonIcon />} />}
            />
            <CardText>
                <TextField record={data[id]} source="body" />
            </CardText>
            <CardText>
                about&nbsp;
                <ReferenceField label="Post" resource="comments" record={data[id]} source="post_id" reference="posts" basePath={basePath}>
                    <TextField source="title" />
                </ReferenceField>
            </CardText>
            <CardActions style={{ textAlign: 'right' }}>
                <EditButton resource="posts" basePath={basePath} record={data[id]} />
            </CardActions>
        </Card>
    )}
    </div>
);
CommentGrid.defaultProps = {
    data: {},
    ids: [],
};

export const CommentList = (props) => (
    <List title="All comments" {...props}>
        <CommentGrid />
    </List>
);

如你所见,没有任何东西阻止你使用<Field>组件在自己的组件之内..。另外, 请注意, 组件构建链接需要basePath组件, 它也会被注入。

results matching ""

    No results matching ""