## 按钮加载逻辑 1. 整个列表页只有一个Grid组件,却动态加载出了按钮,我们不妨看一看这个组件是如何实现的 2. 点进Grid组件,拉到最底下查看render返回,发现封装了3个子组件 ~~~ <Card bordered={false} {...cardProps}> <div className={styles.swordPage}> <SearchBox onSubmit={this.handleSearch} onReset={this.handleFormReset}> {renderSearchForm(this.handleFormReset)} </SearchBox> <ToolBar buttons={buttons} renderLeftButton={renderLeftButton} renderRightButton={renderRightButton} onClick={this.handelToolBarClick} /> <StandardTable rowKey={rowKey || 'id'} selectedRows={selectedRows} loading={loading} columns={columns} data={data} onSelectRow={this.handleSelectRows} onChange={this.handleStandardTableChange} scroll={scroll} tblProps={tblProps} size="middle" /> </div> </Card> ~~~ 3. 这3个组件分别为 `SearchBox` 、`ToolBar`、 `StandardTable` ,我们主要来看`ToolBar` 4. `ToolBar`传入了4个参数:`buttons` 、`renderLeftButton` 、`renderRightButton`、`onClick` 5. buttons就是根据列表页传入的菜单code,通过执行getButton方法从而获取到的按钮集合 ~~~ export default class Grid extends PureComponent { constructor(props) { super(props); this.state = { current: 1, size: 10, formValues: {}, selectedRows: [], buttons: getButton(props.code), }; } } ~~~ 6. 进入ToolBar查看源码,发现其实很简单,就是根据buttons数据集合动态生成了按钮。当中有一点需要注意的是 `buttons.filter(button => button.action === 1 || button.action === 3)`,他根据action字段来判断,这个action代表按钮类型:1:只有工具栏才出现;2:只有表格行才出现;3:两者都出现。 ~~~ export default class ToolBar extends PureComponent { render() { const { buttons, renderLeftButton, renderRightButton, onClick } = this.props; return ( <div className={styles.operator}> <div> {buttons .filter(button => button.action === 1 || button.action === 3) .map(button => ( <Button key={button.code} icon={button.source} type={ button.alias === 'delete' ? 'danger' : button.alias === 'add' ? 'primary' : 'default' } onClick={() => { onClick(button); }} > <FormattedMessage id={`button.${button.alias}.name`} /> </Button> ))} {renderLeftButton ? renderLeftButton() : null} {renderRightButton ? ( <div style={{ float: 'right', marginRight: '20px' }}>{renderRightButton()}</div> ) : null} </div> </div> ); } } ~~~ 7. 其中都 `renderLeftButton` 、`renderRightButton`则是提供大家这列表页自定义的按钮,传入组件,从而生成,不受限于通过菜单接口返回的数据 8. `onClick` 则是组件定义的一些默认点击事件,大家也可以自行拓展,下面是封装的方法。可以看到方法根据菜单中定义的 `按钮别名` 来判断执行不同的操作。若一个code为 notice_add ,一个code为 news_add,两个按钮的别名同为 add,则这两个按钮点击后都会进入第一个判断并执行。若后续有通用的按钮事件,大家也可以在这里自定义拓展。 ~~~ handelClick = (btn, keys = []) => { const { path, alias } = btn; const { btnCallBack } = this.props; const refresh = (temp = true) => this.refreshTable(temp); if (alias === 'add') { if (keys.length > 1) { message.warn('父记录只能选择一条!'); return; } if (keys.length === 1) { router.push(`${path}/${keys[0]}`); return; } router.push(path); return; } if (alias === 'edit') { if (keys.length <= 0) { message.warn('请先选择一条数据!'); return; } if (keys.length > 1) { message.warn('只能选择一条数据!'); return; } router.push(`${path}/${keys[0]}`); return; } if (alias === 'view') { if (keys.length <= 0) { message.warn('请先选择一条数据!'); return; } if (keys.length > 1) { message.warn('只能选择一条数据!'); return; } router.push(`${path}/${keys[0]}`); return; } if (alias === 'delete') { if (keys.length <= 0) { message.warn('请先选择要删除的记录!'); return; } Modal.confirm({ title: '删除确认', content: '确定删除选中记录?', okText: '确定', okType: 'danger', cancelText: '取消', async onOk() { const response = await requestApi(path, { ids: keys.join(',') }); if (response.success) { message.success(response.msg); refresh(); } else { message.error(response.msg || '删除失败'); } }, onCancel() {}, }); return; } if (btnCallBack) { btnCallBack({ btn, keys, refresh }); } }; ~~~ 9. 看到这里,相信大家对封装对列表组件应该有个大致的认识了,下面我们来看一下如果进行自定义按钮的配置。