目录
一:什么是Ant Design?
二:开始使用
三:布局
四:表格
一:什么是Ant Design?
Ant Design是阿里蚂蚁金服团队基于React开发的ui组件,主要用于中后台系统的使用。
官网:https://ant.design/index-cn
设计语言: 随着商业化的趋势,越来越多的企业级产品对更好的用户体验有了进一步的要求。带着这样的一个终极目 标,我们(蚂蚁金服体验技术部)经过大量的项目实践和总结,逐步打磨出一个服务于企业级产品的设计体系 Ant Design 。基于『确定』和『自然』的设计价值观,通过模块化的解决方案,降低冗余的生产成本,让设计者专注于更好的用户体验。 特性: 提炼自企业级中后台产品的交互语言和视觉风格。 开箱即用的高质量 React 组件。 使用 TypeScript 构建,提供完整的类型定义文件。 全链路开发和设计工具体系。
二:开始使用
引入 Ant Design Ant Design 是一个服务于企业级产品的设计体系,组件库是它的 React 实现, antd 被发布为一个 npm 包方便开 发者安装并使用。 在 umi 中,你可以通过在插件集 umi-plugin-react 中配置 antd 打开 antd 插件, antd 插件会帮你引入 antd 并实现按需编译。在 confifig.js 文件中进行配置:
export default {plugins: [ ['umi-plugin-react', { dva: true, // 开启dva功能 antd: true // 开启Ant Design功能}]]};
小试牛刀 接下来,我们开始使用 antd 的组件,以 tabs 组件为例,地址 https://ant.design/components/tabs-cn/ 效果:
看下官方给出的使用示例:
import { Tabs } from 'antd';const TabPane = Tabs.TabPane;function callback(key) {console.log(key);}ReactDOM.render(<Tabs defaultActiveKey="1" onChange={callback}><TabPane tab="Tab 1" key="1">Content of Tab Pane 1</TabPane><TabPane tab="Tab 2" key="2">Content of Tab Pane 2</TabPane><TabPane tab="Tab 3" key="3">Content of Tab Pane 3</TabPane></Tabs>,mountNode);
下面我们参考官方给出的示例,进行使用: 创建 MyTabs.js 文件: import React from 'react'import {Tabs} from 'antd'const TabPane = Tabs.TabPane;const callback = (key) => { console.log(key);}class MyTabs extends React.Component {render() { return (<Tabs defaultActiveKey="1" onChange={callback}><TabPane tab="Tab 1" key="1">Content of Tab Pane 1</TabPane><TabPane tab="Tab 2" key="2">Content of Tab Pane 2</TabPane><TabPane tab="Tab 3" key="3">Content of Tab Pane 3</TabPane></Tabs>)}}export default MyTabs;
效果: 到此,我们已经掌握了antd组件的基本使用。
三:布局
antd 布局: https://ant.design/components/layout-cn/ 在后台系统页面布局中,往往是经典的三部分布局,像这样:下面,我们通过antd组件来完成这个布局。
组件概述 Layout :布局容器,其下可嵌套 Header Sider Content Footer 或 Layout 本身,可以放在任何父容器中。 Header :顶部布局,自带默认样式,其下可嵌套任何元素,只能放在 Layout 中。 Sider :侧边栏,自带默认样式及基本功能,其下可嵌套任何元素,只能放在 Layout 中。 Content :内容部分,自带默认样式,其下可嵌套任何元素,只能放在 Layout 中。 Footer :底部布局,自带默认样式,其下可嵌套任何元素,只能放在 Layout 中。搭建整体框架 在 src 目录下创建 layouts 目录,并且在 layouts 目录下创建 index.js 文件,写入内容:
import React from 'react'import { Layout } from 'antd';const { Header, Footer, Sider, Content } = Layout;class BasicLayout extends React.Component{render(){return ( <Layout> <Sider>Sider</Sider> <Layout> <Header>Header</Header> <Content>Content</Content> <Footer>Footer</Footer> </Layout> </Layout>);}}export default BasicLayout;
需要特别说明的是,在 umi 中约定的目录结构中, layouts/index.js 文件将被作为全局的布局文件。 接下来,配置路由:(非必须) confifig.js 文件: export default { plugins: [ ['umi-plugin-react', { dva: true, // 开启dva功能 antd: true // 开启Ant Design功能}]], routes: [{ path: '/', component: '../layouts' //配置布局路由}]};
进行页面访问: 可以看到,布局已经生成,只是样式优点丑。
子页面使用布局 前面所定义的布局是全局布局,那么,在子页面中如何使用这个全局布局呢? 首先,需要在布局文件中,将 Content 内容替换成 {this.props.children} ,意思是引入传递的内容。
import React from 'react'import { Layout } from 'antd';const { Header, Footer, Sider, Content } = Layout;class BasicLayout extends React.Component{render(){ return ( <Layout> <Sider>Sider</Sider> <Layout> <Header>Header</Header> <Content>{this.props.children}</Content> <Footer>Footer</Footer> </Layout> </Layout>);}}export default BasicLayout;
接下来配置路由(注意,在布局路由下面进行配置): 说明:下面的路由配置,是表明你需要通过手动配置的方式上进行访问页面,而不采用 umi 默认的路由方式。 export default { plugins: [ ['umi-plugin-react', { dva: true, // 开启dva功能 antd: true // 开启Ant Design功能 }]], routes: [{ path: '/', component: '../layouts', //配置布局路由 routes: [ //在这里进行配置子页面 { path: '/myTabs', component: './myTabs'}]}]};
进行访问测试: 可以看到,在MyTabs组件中已经应用了全局的布局。其他子页面也就同理了。
美化页面 接下来,对页面做一些美化的工作:import React from 'react'import { Layout } from 'antd';const { Header, Footer, Sider, Content } = Layout;class BasicLayout extends React.Component{render(){return ( <Layout> <Sider width={256} style={{ minHeight: '100vh', color: 'white' }}> Sider </Sider> <Layout> <Header style={{ background: '#fff', textAlign: 'center', padding: 0 }}>Header</Header> <Content style={{ margin: '24px 16px 0' }}> <div style={{ padding: 24, background: '#fff', minHeight: 360 }}> {this.props.children} </div> </Content> <Footer style={{ textAlign: 'center' }}>后台系统 ©2022 Created by 大唐霸业</Footer></Layout></Layout>);}}export default BasicLayout;
效果: 引入导航条 使用 Menu 组件作为导航条: https://ant.design/components/menu-cn/
import React from 'react'import {Layout, Menu, Icon} from 'antd';const {Header, Footer, Sider, Content} = Layout;const SubMenu = Menu.SubMenu;class BasicLayout extends React.Component {constructor(props){super(props);this.state = {collapsed: false,}}render() {return ( <Layout> <Sider width={256} style={{minHeight: '100vh', color: 'white'}}> <div style={{ height: '32px', background: 'rgba(255,255,255,.2)', margin: '16px'}}/> <Menu defaultSelectedKeys={['2']} defaultOpenKeys={['sub1']} mode="inline" theme="dark" inlineCollapsed={this.state.collapsed} > <Menu.Item key="1"> <Icon type="pie-chart"/> <span>Option 1</span> </Menu.Item> <Menu.Item key="2"> <Icon type="desktop"/> <span>Option 2</span> </Menu.Item> <Menu.Item key="3"> <Icon type="inbox"/> <span>Option 3</span> </Menu.Item> <SubMenu key="sub1" title={<span><Icon type="mail"/> <span>Navigation One</span></span>}> <Menu.Item key="5">Option 5</Menu.Item> <Menu.Item key="6">Option 6</Menu.Item> <Menu.Item key="7">Option 7</Menu.Item> <Menu.Item key="8">Option 8</Menu.Item> </SubMenu> <SubMenu key="sub2" title={<span><Icon type="appstore"/> <span>Navigation Two</span></span>}> <Menu.Item key="9">Option 9</Menu.Item> <Menu.Item key="10">Option 10</Menu.Item> <SubMenu key="sub3" title="Submenu"> <Menu.Item key="11">Option 11</Menu.Item> <Menu.Item key="12">Option 12</Menu.Item> </SubMenu> </SubMenu> </Menu> </Sider> <Layout> <Header style={{background: '#fff', textAlign: 'center', padding: 0}}>Header</Header> <Content style={{margin: '24px 16px 0'}}> <div style={{padding: 24, background: '#fff', minHeight: 360}}> {this.props.children} </div> </Content> <Footer style={{textAlign: 'center'}}>后台系统 ©2018 Created by 大唐霸业</Footer> </Layout> </Layout>);}}export default BasicLayout;
效果: 为导航添加链接 下面,我们对左侧的导航条添加链接,点击相应的链接在右侧进行相应页面的显示。 在 src 目录下创建 user 目录,并且在 user 目录下创建 UserAdd.js 和 UserList.js 文件,用于模拟实现新增用户和查询用户列表功能。
UserAdd.js :
import React from 'react'class UserAdd extends React.Component{render(){return (<div>新增用户</div>);}}export default UserAdd;
UserList.js : import React from 'react'class UserList extends React.Component{render(){return (<div>用户列表</div>);}}export default UserList;
接下来,配置路由: export default { plugins: [ ['umi-plugin-react', { dva: true, // 开启dva功能 antd: true // 开启Ant Design功能 }] ], routes: [{ path: '/', component: '../layouts', //配置布局路由 routes: [ { path: '/myTabs', component: './myTabs' }, { path: '/user', routes: [ { path: '/user/list', component: './user/UserList' }, { path: '/user/add', component: './user/UserAdd' } ] } ] }]};
为菜单添加链接: import React from 'react'import {Layout, Menu, Icon} from 'antd';import Link from 'umi/link';const {Header, Footer, Sider, Content} = Layout;const SubMenu = Menu.SubMenu;class BasicLayout extends React.Component {constructor(props){super(props);this.state = {collapsed: false,}}render() { return ( <Layout> <Sider width={256} style={{minHeight: '100vh', color: 'white'}}> <div style={{ height: '32px', background: 'rgba(255,255,255,.2)', margin: '16px'}}/> <Menu defaultSelectedKeys={['1']} defaultOpenKeys={['sub1']} mode="inline" theme="dark" inlineCollapsed={this.state.collapsed} > <SubMenu key="sub1" title={<span><Icon type="user"/><span>用户管 理</span></span>}> <Menu.Item key="1"> <Link to="/user/list">用户列表</Link> </Menu.Item> <Menu.Item key="2"> <Link to="/user/add">新增用户</Link> </Menu.Item> </SubMenu> </Menu> </Sider> <Layout> <Header style={{background: '#fff', textAlign: 'center', padding: 0}}>Header</Header> <Content style={{margin: '24px 16px 0'}}> <div style={{padding: 24, background: '#fff', minHeight: 360}}> {this.props.children} </div> </Content> <Footer style={{textAlign: 'center'}}>后台系统 ©2018 Created by 大唐霸业</Footer> </Layout> </Layout> ); } } export default BasicLayout;
注意:这里使用了 umi 的 link 标签,目的是出现记录点击的菜单。 测试:
四:表格
基本用法 参考官方文档进行实现: https://ant.design/components/table-cn/ 改造 UserList.js 页面:import React from 'react'import {Table, Divider, Tag, Pagination } from 'antd';const {Column} = Table;const data = [{key: '1',name: '张三',age: 32,address: '上海市',tags: ['程序员', '帅气'],}, {key: '2',name: '李四',age: 42,address: '北京市',tags: ['屌丝'],}, {key: '3',name: '王五',age: 32,address: '杭州市',tags: ['高富帅', '富二代'],}];class UserList extends React.Component {render() { return ( <div> <Table dataSource={data} pagination= {{position:"bottom",total:500,pageSize:10, defaultCurrent:3}}> <Column title="姓名" dataIndex="name" key="name" /> <Column title="年龄" dataIndex="age" key="age" /> <Column title="地址" dataIndex="address" key="address" /> <Column title="标签" dataIndex="tags" key="tags" render={tags => ( <span> {tags.map(tag => <Tag color="blue" key={tag}>{tag} </Tag>)} </span> )} /> <Column title="操作" key="action" render={(text, record) => ( <span> <a href="javascript:;">编辑</a> <Divider type="vertical"/> <a href="javascript:;">删除</a> </span> )} /> </Table> </div> );}} export default UserList;
实现效果: 将数据分离到 model 中 model 的实现: UserListData.js
import request from "../util/request";export default { namespace: 'userList', state: { list: [] }, effects: { *initData(params, sagaEffects) { const {call, put} = sagaEffects; const url = "/ds/user/list"; let data = yield call(request, url); yield put({ type : "queryList", data : data }); } }, reducers: { queryList(state, result) { let data = [...result.data]; return { //更新状态值 list: data } } }}
修改 UserList.js 中的逻辑: import React from 'react';import { connect } from 'dva';import {Table, Divider, Tag, Pagination } from 'antd';const {Column} = Table;const namespace = 'userList';@connect((state)=>{return { data : state[namespace].list}}, (dispatch) => { return { initData : () => { dispatch({ type: namespace + "/initData" }); } } })class UserList extends React.Component { componentDidMount(){ this.props.initData(); }render() { return ( <div> <Table dataSource={this.props.data} pagination= {{position:"bottom",total:500,pageSize:10, defaultCurrent:3}}> <Column title="姓名" dataIndex="name" key="name" /> <Column title="年龄" dataIndex="age" key="age" /> <Column title="地址" dataIndex="address" key="address" /> <Column title="标签" dataIndex="tags" key="tags" render={tags => ( <span> { tags.map(tag => <Tag color="blue" key={tag}>{tag} </Tag>)} </span> )} /> <Column title="操作" key="action" render={(text, record) => ( <span> <a href="javascript:;">编辑</a> <Divider type="vertical"/> <a href="javascript:;">删除</a> </span> )} /> </Table> </div>);}} export default UserList;
mock 数据: MockListData.js export default {'get /ds/list': function (req, res) {res.json({data: [1, 2, 3, 4],maxNum: 4});},'get /ds/user/list': function (req, res) {res.json([{key: '1',name: '张三1',age: 32,address: '上海市',tags: ['程序员', '帅气'],}, {key: '2',name: '李四',age: 42,address: '北京市',tags: ['屌丝'],}, {key: '3',name: '王五',age: 32,address: '杭州市',tags: ['高富帅', '富二代'],}]);}}
测试结果: