antd ProComponent 常用操作總結(jié)

相信很多同學(xué)都用過 Ant Design 這一 react 著名組件庫,ProComponents 則是在 antd 之上進(jìn)行封裝的頁面級(jí)組件庫(指一個(gè)組件就可以搞定一個(gè)頁面)。它同時(shí)也是 Ant Design Pro 中后臺(tái)框架所用的主要組件庫。如果你手上有要用 react 開發(fā)的中后臺(tái)新項(xiàng)目又人手不夠的話,我強(qiáng)烈推薦你體驗(yàn)一下這個(gè)庫??梢詷O大的減少日常 CRUD 的代碼量并統(tǒng)一風(fēng)格。

在 ProComponent 中,最為核心的就是 ProForm(表單)和 ProTable(表格)兩個(gè)組件,面對(duì)數(shù)量繁多的配置項(xiàng),很多人都會(huì)在文檔中迷失自我,本文就來介紹一些常見的配置,希望可以對(duì)你有所幫助。

本文的所有內(nèi)容均來自于 ProComponent 官方文檔,如果你遇到了實(shí)在解決不了的問題時(shí)請(qǐng)熟讀文檔或者去 issue 區(qū) 里查一查。我也很推薦你在使用一段時(shí)間后重讀一下 官方文檔 - 通用配置總覽。相信可以讓你對(duì) pro 組件有更全面的了解

ProTable

官方文檔,ProTable 最大的好處就是它集成了表格的查詢條件和分頁配置。只需要配置表格列就可以自動(dòng)生成對(duì)應(yīng)的查詢 form。除此之外它提供的插槽和細(xì)節(jié)小功能用起來也十分舒服。

1、基礎(chǔ)流程

先來簡單介紹一下基本的使用,主要就是兩部分:表格列配置、查詢請(qǐng)求,最后把他倆塞給 ProTable 就完事了:

import { fetchCompanyList } from '@/service';
import ProTable from '@ant-design/pro-table';
 
const CompanyList = () => {
    // 表格列配置項(xiàng)
    const columns = [
        {
            title: '企業(yè)名稱',
            dataIndex: 'corName',
        },
        {
            title: '申請(qǐng)日期',
            dataIndex: 'applyDate',
            valueType: 'date',
            align: 'center'
        },
    ];

    /** 獲取數(shù)據(jù) */
    const getData = async (params) => {
        // 組裝查詢參數(shù),比如這里用 pageIndex 代替了 current
        const query = {
            ...params,
            pageIndex: params.current
        };
        delete query.current;

        // 發(fā)起請(qǐng)求
        const { data, success } = await fetchCompanyList(query);

        // 格式化返回?cái)?shù)據(jù)
        return {
            data: data.records,
            success,
            total: data.total,
        };
    };

    return (
        <ProTable
            columns={columns}
            request={getData}
            rowKey="id"
        />
    );
};

然后你就得到了這個(gè)簡單但五臟俱全的表格:

在 ProTable 中查詢條件和表格列是一一對(duì)應(yīng)的,也就是說每個(gè)列都會(huì)生成一個(gè)對(duì)應(yīng)的查詢條件,注意列配置中的 valueType 字段,它標(biāo)注了這個(gè)字段是一個(gè)日期,然后 ProTable 就會(huì)按照對(duì)應(yīng)的格式渲染表格字段和查詢表單項(xiàng)。

注意這個(gè) valueType 是 ProComponent 的靈魂,你可以在 這里 找到其支持的所有 valueType。

在發(fā)起查詢時(shí),你所有的查詢條件和分頁參數(shù)都會(huì)被傳遞給 request 參數(shù)對(duì)應(yīng)的函數(shù)上,最后把查詢到的結(jié)果按照給定的格式返回出去即可,注意這個(gè)函數(shù)可以是異步函數(shù),ProTable 會(huì)根據(jù)這個(gè)函數(shù)的狀態(tài)自動(dòng)渲染相關(guān)的加載動(dòng)畫,非常舒服。

2、隱藏查詢條件

ProTable 默認(rèn)會(huì)顯示所有列的查詢條件,如果你想隱藏指定列的查詢條件,可以在列配置項(xiàng)里添加 hideInSearch

const columns = [
        {
            title: '企業(yè)名稱',
            dataIndex: 'corName',
            // 添加這個(gè)屬性
            hideInSearch: true
        },
        // ...
    ];

或者如果想直接隱藏整個(gè)查詢表單的話,可以在 ProTable 上關(guān)閉 search 項(xiàng):

<ProTable
    // 不顯示搜索表單
    search={false}
    columns={columns}
    request={getData}
    rowKey="id"
/>

3、tag 列及查詢條件

下圖這種標(biāo)簽列在表格里是非常常見的,下面就來介紹下怎么實(shí)現(xiàn):

import { keyBy } from 'lodash';
import { Tag } from 'antd';

/** 企業(yè)申請(qǐng)狀態(tài)配置項(xiàng) */
const REQUEST_STATUS_OPTION = [
    { text: '待審核', value: 0, color: '' },
    { text: '審核通過', value: 1, color: 'green' },
    { text: '審核不通過', value: 2, color: 'red' }
]

// {
//   '0': { text: '待審核', /** ... */ },
//   '1': { text: '審核通過', /** ... */ },
//   '2': { text: '審核不通過', /** ... */ },
// }
const requestStatusEnum = keyBy(REQUEST_STATUS_OPTION, 'value')

// 表格行配置項(xiàng)
const columns = [
    {
        title: '審批狀態(tài)',
        dataIndex: 'status',
        valueType: 'select',    
        valueEnum: requestStatusEnum,
        // 設(shè)置為多選
        // fieldProps: { mode: 'multiple' },
        render: (text, { status }) => {
            const tagStatus = requestStatusEnum[status] || { color: '', text: '未知' };
            return <Tag color={tagStatus.color}>{tagStatus.text}</Tag>;
        },
    },
    // ...
];

首先,在列配置項(xiàng)里使用 valueType: 'select' 將查詢項(xiàng)渲染成下拉框,然后使用 valueEnum 屬性配置下拉框的內(nèi)容,注意它接受的是一個(gè) kv 對(duì)象,鍵為選項(xiàng) value,值中的 text 屬性作為選項(xiàng)的 label。這里直接使用 lodash 的 keyBy 來生成。最后通過列配置的 render 屬性渲染標(biāo)簽,這里的用法和 antd 里是一樣的。

之所以把選項(xiàng)搞成數(shù)組形式然后再轉(zhuǎn)換成 kv 對(duì)象,是因?yàn)?ProForm 那邊也同樣會(huì)用到這個(gè)配置,而那里的下拉框是需要數(shù)組形式的。

這里你也可以通過設(shè)置列配置項(xiàng)的 fieldProps: { mode: 'multiple' } 來將下拉框設(shè)置成多選。:

注意,列配置項(xiàng) fieldProps 里的配置會(huì)被透傳到 valueType 對(duì)應(yīng)的 antd 組件上,也就是說這里的多選配置實(shí)際上是 antd Select 組件的配置。

ProTable 官網(wǎng)介紹

4、查詢默認(rèn)值

你可以通過列表項(xiàng)的 initialValue 來給查詢表單項(xiàng)設(shè)置默認(rèn)值:

const columns = [
    {
        title: '申請(qǐng)日期',
        dataIndex: 'applyDate',
        valueType: 'date',
        align: 'center',
        // 設(shè)置默認(rèn)值
        initialValue: '2021-7-1'
    },
    // ...
];

5、列寬調(diào)整

ProTable 默認(rèn)會(huì)等分所有列,想調(diào)整指定列寬的話可以修改列配置的 width 屬性,支持百分比和數(shù)字。

// 表格行配置項(xiàng)
const columns = [
    {
        title: '企業(yè)名稱',
        dataIndex: 'corName',
        // 設(shè)置為百分比
        width: '70%'
    },
    {
        title: '申請(qǐng)日期',
        dataIndex: 'applyDate',
        valueType: 'date',
        // 設(shè)置為固定值
        width: 240
    }
];

這個(gè)配置在 ProTable 的文檔里并沒有標(biāo)注(起碼我沒找到),但是實(shí)際上,所有 antd Table Column 支持的配置項(xiàng)都可以用在這里。

而 ProTable 組件則會(huì)把自己 form 屬性上的對(duì)象傳遞給自己內(nèi)部封裝的 antd Form 組件,你可以用這個(gè)屬性來自定義表單 form:

ProTable 入?yún)⑽臋n

6、查詢條件順序調(diào)整

ProTable 默認(rèn)按照列配置的索引排列查詢條件,你可以通過指定列配置項(xiàng)中的 order 來調(diào)整查詢條件的順序,其值越大就越靠前:

const columns = [
    {
        title: '企業(yè)名稱',
        dataIndex: 'corName',
        order: 9
    },
    {
        title: '申請(qǐng)日期',
        dataIndex: 'applyDate',
        valueType: 'date',
        align: 'center',
        order: 10
    },
];
日期的查詢條件跑到了名稱前面

7、查詢條件長度調(diào)整

你可以通過指定列配置的 colSize 項(xiàng)來調(diào)整具體查詢條件的長度,官方介紹如下:

默認(rèn)情況下一個(gè) colSize 的長度就是 8 span,那么也就是說 colSize: 4 時(shí)就可以占滿一行:

const columns = [
    {
        title: '企業(yè)名稱',
        dataIndex: 'corName',
        colSize: 4
    },
    // ...
];

注意這個(gè)值沒必要是整數(shù),你可以設(shè)置為 0.5 來將其縮短,但是要注意最后相乘得到的 span 值最好是個(gè)整數(shù)。

8、時(shí)間查詢條件改為范圍

列表中時(shí)間列的查詢條件一般都是個(gè)范圍,如下:

但是默認(rèn)的 valueType: 'date' 只會(huì)顯示單個(gè)日期選擇器,所以我們需要使用其他方法來實(shí)現(xiàn)這個(gè)需求,具體做法也很簡單,把表格列的查詢項(xiàng)關(guān)掉,然后放置一個(gè)時(shí)間范圍的查詢條件,注意時(shí)間范圍使用 hideInTable 參數(shù)讓它不會(huì)顯示在表格里:

// 表格行配置項(xiàng)
const columns = [
    {
        title: '申請(qǐng)日期',
        dataIndex: 'applyDate',
        valueType: 'date',
        hideInSearch: true
    },
    {
        title: '申請(qǐng)日期',
        dataIndex: 'applyDateRange',
        valueType: 'dateRange',
        fieldProps: { placeholder: ['開始時(shí)間', '結(jié)束時(shí)間'] },
        hideInTable: true
    },
];

然后你就可以在 request 里處理他們:

const getData = async (params) => {
    const query = {
        ...params,
        applyDateStart: (params.applyDateRange || [])[0],
        applyDateEnd: (params.applyDateRange || [])[1]
    };
    delete query.applyDateRange;

    // 發(fā)起請(qǐng)求 ...
};

你可能想說直接把日期列的 valueType 設(shè)置為 dateRange 可以么?實(shí)際上不行的,因?yàn)檫@會(huì)讓它在表格里也顯示成時(shí)間范圍的形式 :xxx - xxx。

ProForm

ProForm 文檔,ProFormFields 表單項(xiàng)文檔。ProForm 的好處是封裝了不同的表單外觀,你只需要切換一個(gè)字段就可以把頁面表單切換成彈出表單或者抽屜表單。除此之外還封裝了提交和重置行為、以及對(duì)常用的表單項(xiàng)都進(jìn)行了封裝。

1、基礎(chǔ)流程

ProTable 的用法更加簡單,在 ProForm 標(biāo)簽里插入封裝好的 表單項(xiàng)。然后給 onFinish 設(shè)置一個(gè)函數(shù)即可,這個(gè)函數(shù)會(huì)接受到 通過校驗(yàn) 的表單項(xiàng),然后你就可以在這里訪問后端進(jìn)行提交了。

import ProForm, {
    ProFormRadio,
    ProFormText,
    ProFormDatePicker,
} from '@ant-design/pro-form';

const PolicyDetail = (props) => {
    // 只有通過校驗(yàn)之后才會(huì)觸發(fā)這個(gè)方法
    const onSubmit = async (values) => {
        console.log(values);
    };

    return (
        <ProForm onFinish={onSubmit}>
            <ProFormText
                name="name"
                label="名稱"
                placeholder="請(qǐng)輸入名稱"
            />
            <ProFormRadio.Group
                name="status"
                label="狀態(tài)"
                options={[
                    { label: '已生效', value: '已生效' },
                    { label: '已作廢', value: '已作廢' }
                ]}
                rules={[{ required: true, message: '狀態(tài)不能為空' }]}
            />
            <ProFormDatePicker
                name="publishTime"
                label="時(shí)間"
                placeholder="請(qǐng)選擇時(shí)間"
                rules={[{ required: true, message: '時(shí)間不能為空' }]}
            />
        </ProForm>
    );
};

注意,在 ProForm 中,select, checkbox, radio, radioButton 這些表單項(xiàng)都支持通過 options 參數(shù)配置選項(xiàng)內(nèi)容,其值為 { value: '', label: ''} 格式的數(shù)組。具體介紹可以看 這里。

注意,所有的 ProForm 表單組件都是用 Form.Item + 對(duì)應(yīng)的組件封裝的來的,都支持使用 fieldProps 屬性來支持設(shè)置輸入組件的 props。

也就是說,fieldProps 參數(shù)里的屬性都會(huì)被透傳給內(nèi)部的輸入組件,而直接設(shè)置給 ProForm 表單組件的字段會(huì)被透傳給 Form.Item。切記切記,不要一看到表單項(xiàng)列表里一點(diǎn)屬性都沒貼就覺得這玩意沒法用了。

這一點(diǎn)在 ProFormFields - 表單項(xiàng) (ant.design) 最開頭就說了,但是有很多人都是直接點(diǎn)下面的具體組件看文檔,結(jié)果根本不知道這一點(diǎn)從而又浪費(fèi)了很多時(shí)間,比如我。

2、對(duì)齊提交按鈕

大多數(shù)表單開發(fā)的習(xí)慣都是底部的操作按鈕組和字段輸入框?qū)R,但如果你給 form 配置了 layout="horizontal"labelCol={{ span: 4 }} 后就會(huì)發(fā)現(xiàn),底部的按鈕組還是左側(cè)開始的。

解決這個(gè)對(duì)齊問題需要用到 ProForm 的 submitter 屬性,而其中的 render 函數(shù)則可以控制底部按鈕組的渲染,這個(gè)函數(shù)的第二個(gè)入?yún)⑹且粋€(gè)數(shù)組,其元素分別是已經(jīng)渲染好的重置和提交按鈕,如果你有需要的話也可以在這里進(jìn)行更復(fù)雜的自定義行為:

<ProForm
    submitter={{
        render: (_, dom) => (
            <Form.Item wrapperCol={{ offset: 4 }}>
                <Space>{dom}</Space>
            </Form.Item>
        ),
    }}
    // ...
>
    {/* ... */}
</ProForm>
期望對(duì)齊

注意我上面 wrapperCol 的 offset 是 4,你需要根據(jù)你的 ProForm 配置自行調(diào)整。

3、數(shù)據(jù)回填

想回填數(shù)據(jù)的話需要用到 ProForm 的 initialValues,整個(gè)表單的數(shù)據(jù)都應(yīng)該在這里設(shè)置。注意在數(shù)據(jù)獲取到之前不能渲染表單,不然初始值就無效了。

import React, { useState, useEffect } from 'react';
import ProForm from '@ant-design/pro-form';
import { Skeleton } from 'antd';
import { isEmpty } from 'lodash';
import { getDetail } from '@/service';

const Detail = () => {
    // 詳情數(shù)據(jù)
    const [detail, setDetail] = useState({});

    // 獲取詳情
    useEffect(async () => {
        const { data } = await getDetail();
        setDetail(data);
    }, []);

    const loadingPage = isEmpty(detail);
    
    // 數(shù)據(jù)獲取到之前展示加載動(dòng)畫,讓 form 渲染時(shí)肯定可以得到初始值
    return loadingPage ? (
        <Skeleton active />
    ) : (
        <ProForm initialValues={detail}>
            {/* ... */}
        </ProForm>
    )
};

我注意到有很多人在回填表單數(shù)據(jù)的時(shí)候喜歡用 form.setFieldsValue 設(shè)置,但是這么做是不對(duì)的,一方面在數(shù)據(jù)抵達(dá)的時(shí)候 form 表單項(xiàng)可能還沒加載出來,另一方面使用 initialValues 可以讓重置按鈕可以恢復(fù)到初始值,而不是重置成全空表單。

4、表單項(xiàng)聯(lián)動(dòng)

表單里經(jīng)常會(huì)出現(xiàn)如下這種表單項(xiàng)聯(lián)動(dòng)的需求:

ProComponent 中提供了 ProFormDependency 組件可以響應(yīng)式的處理這種需求:

import ProForm, { ProFormRadio, ProFormDependency } from '@ant-design/pro-form';

<ProFormRadio.Group
    name="status"
    label="結(jié)論"
    options={[
        { label: '審核通過', value: 1 },
        { label: '審核不通過', value: 2 }
    ]}
/>

<ProFormDependency name={['status']}>
    {({ status }) => {
        if (!status || status === 1) return null;
        return (<ProFormTextArea
            name="refuseReason"
            label="駁回原因"
            placeholder="請(qǐng)?zhí)顚戱g回原因"
        />);
    }}
</ProFormDependency>

ProFormDependency 在 name 字段里綁定的值變更后會(huì)自動(dòng)觸發(fā) children 里的函數(shù)進(jìn)行渲染。

5、表單項(xiàng)聯(lián)動(dòng) - 異步

上面的例子里提到了如何進(jìn)行同步的聯(lián)動(dòng),但是這可是在 render 里,我們不能直接設(shè)置一個(gè) async 函數(shù)來阻塞渲染。想要進(jìn)行異步聯(lián)動(dòng)我們需要使用 onValuesChange 監(jiān)聽值變更并使用 formRef 修改表單值:

代碼如下:

import React, { useRef } from 'react';
import ProForm, { ProFormSelect, ProFormUploadButton } from '@ant-design/pro-form';

/** 附件獲取接口 mock */
const getFileById = async (id) => {
    return new Promise(resolve => setTimeout(() => {
        if (id === 1) resolve([]);
        else resolve([
            { name: '測(cè)試文件1.png', url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png' }
        ])
    }, 500))
}

const MyForm = (props) => {
    const formRef = useRef(undefined);

    /** 變化時(shí)監(jiān)聽,并將返回值重設(shè)回 form */
    const onChange = async ({ selectVal }) => {
        const file = await getFileById(selectVal);
        formRef.current.setFieldsValue({ file });
    }

    return (
        <ProForm
            layout="horizontal"
            labelCol={{ span: 4 }}
            onValuesChange={onChange}
            formRef={formRef}
        >
            <ProFormSelect
                options={[
                    { label: '沒有附件', value: 1 },
                    { label: '有附件', value: 2 },
                ]}
                name="selectVal"
                label="選項(xiàng)"
            />

            <ProFormUploadButton
                label="選項(xiàng)附件"
                name="file"
                // 更好的顯示附件
                readonly
                fieldProps={{
                    showUploadList: { showRemoveIcon: false }
                }}
            />
        </ProForm>
    );
};

在使用 ProForm 時(shí)盡量不要使用單獨(dú)表單項(xiàng)的 onChange 事件,因?yàn)?ProForm 會(huì)自動(dòng)注冊(cè)這個(gè)回調(diào)來接管數(shù)據(jù)量,手動(dòng)調(diào)用會(huì)導(dǎo)致覆蓋其注冊(cè),從而出現(xiàn)某些表單數(shù)據(jù)失去響應(yīng)式的問題。

并且注意其中的 ProFormUploadButton 組件,這里使用了它的 readonly 屬性來隱藏了上傳按鈕,ProForm 所有的表單項(xiàng)都支持這個(gè)字段并提供了特別的顯示效果,所以比單純的 disabled 更好(除此之外還使用了 fieldProps 自定義內(nèi)部的 Upload 組件的屬性)。

寫在最后

可以看到本文里的配置基本都是非常簡單的,但是鑒于其數(shù)量眾多的配置項(xiàng),一開始使用的時(shí)候經(jīng)常會(huì)看文檔好久才能找到期望的配置寫法。我在一開始使用的時(shí)候也因此浪費(fèi)了不少時(shí)間,再加上網(wǎng)上關(guān)于 ProComponent 的文章幾乎等于沒有,所以萌生了整理這個(gè)文檔的想法。

如果你也遇到了類似的困擾了你半天但最終配置很簡單的情況,歡迎評(píng)論交流。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容