react+antd项目初始化

总结

1 项目创建

1.2 命令创建

create-react-app admin

1.3 模块分类

1.3.1 模块功能
  • assets 存放静态文件的文件目录,比如图片
  • Components 存放组件,比如布局组件,登录组件
  • Pages 存放页面,开发中的每一个页面
  • Routers 存放页面跳转的路由

1.4 使用antd UI

1.4.1 安装antd

使用框架 cnpm i antd -S

使用图标 cnpm install --save @ant-design/icons

1.4.2 配置antd

在App.css中添加 @import '~antd/dist/antd.css';

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hPhRgzmD-1620631198088)(C:\Users\皮卡丘\AppData\Roaming\Typora\typora-user-images\image-20210118113743379.png)]

1.5 使用less

1.5.1 安装less

cnpm i sass node-sass -S

1.5.2 配置使用

直接创建less文件,编写less样式就可以使用

1.6 使用路由

1.6.1 安装router

cnpm i react-router-dom react-router -S

1.6.2 使用路由

直接引入路由即可使用

1.7 使用redux

1.7.1 安装redux

cnpm i redux react-redux react-hot-loader -S

1.7.2 使用redux

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jo1dEktl-1620631198091)(C:\Users\皮卡丘\AppData\Roaming\Typora\typora-user-images\image-20210118144228286.png)]

  • Actions 封装的行为

    import {ADD_COUNT,SUB_COUNT } from '../Types'
    export const addCount = value=> {
        return{
            type:ADD_COUNT,
            value
        }
    }
    export const subCount = value => {
        return{
            type:SUB_COUNT,
            value
        }
    }
    
    
  • reducer 出来行为的中间件

    import {ADD_COUNT,SUB_COUNT} from '../Types'
    const defaultProp = {
        count:0
    }
    export default (state=defaultProp,action)=>{
        switch (action.type) {
            case ADD_COUNT:
                const newState = JSON.parse(JSON.stringify(state))
                newState.count += action.value
                return newState
            case SUB_COUNT:
                const subState = JSON.parse(JSON.stringify(state))
                subState.count -= action.value
                return subState
            default:
                return state
        }
    }
    
    
  • Types 全局常量

export const ADD_COUNT = 'ADD_COUNT'
export const SUB_COUNT = 'SUB_COUNT'

  • App.js
import React,{Component} from 'react'
import {Button} from 'antd'
import {connect} from 'react-redux'
import './App.css'
import {addCount,subCount} from './Store/Actions'
class APP extends Component{
    constructor() {
        super();
    }
    render() {
        return (
            <div>
                <Button type='primary' onClick={this.props.subCount}>-</Button>
                <span style={{margin:'0 10px',
                    fontSize:20}}>{this.props.count}</span>
                <Button type='primary' onClick={this.props.addCount}>+</Button>
            </div>
        )
    }
}
const mapProps = state =>{
    return{
        count:state.count
    }
}
const  mapActions = dispatch =>{
    return{
        addCount(){
            dispatch(addCount(4))
        },
        subCount(){
            dispatch(subCount(2))
        }
    }
}
export default connect(mapProps,mapActions)(APP)

1.8 使用请求

1.8.1 安装redux-thunk

cnpm i redux-thunk axios -S

1.8.2 配置使用
  • Actions中 编写请求

    export const getList = value => {
        return{
            type:GET_LIST,
            value
        }
    }
    
    export const getTodos = number => dispatch => {
        axios
            .get('http://jsonplaceholder.typicode.com/todos')
            .then(todos => {
                // 把actions 发送给 reducer
                console.log(todos)
                dispatch(getList(todos))
            })
    }
    
  • reducer 处理行为

    case GET_LIST:
                const newList = JSON.parse(JSON.stringify(state))
                newList.todos = action.value.data
                return newList
    
  • store/index.js

    import { createStore, applyMiddleware, compose } from 'redux'
    
    import reducer from './reducer'
    import thunk from 'redux-thunk';
    
    
    const composeEnhancers =
        typeof window === 'object' &&
        window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?
            window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;
    
    const enhancer = composeEnhancers(
        applyMiddleware(thunk),
    );
    
    const store = createStore(
        reducer,//构建初始的数据
        enhancer
    )
    export default store
    
    
  • App.js 中使用

import React,{Component} from 'react'
import {Button} from 'antd'
import {connect} from 'react-redux'
import './App.css'
import {addCount,subCount,getTodos} from './Store/Actions'
class APP extends Component{
    constructor() {
        super();
    }
    componentDidMount() {
        this.props.getTodo()
    }
    render() {
        return (
            <div>
                <Button type='primary' onClick={this.props.subCount}>-</Button>
                <span style={{margin:'0 10px',
                    fontSize:20}}>{this.props.count}</span>
                <Button type='primary' onClick={this.props.addCount}>+</Button>
            </div>
        )
    }
}
const mapProps = state =>{
    return{
        count:state.count
    }
}
const  mapActions = dispatch =>{
    return{
        addCount(){
            dispatch(addCount(4))
        },
        subCount(){
            dispatch(subCount(2))
        },
        getTodo(){
            dispatch(getTodos())
        }
    }
}
export default connect(mapProps,mapActions)(APP)

2 项目开发

  • 模拟数据’json-server’
    • 查 get
    • 增 post
    • 删 delete
    • 改 patch

2.1 登录页面

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jozzqpbk-1620631198093)(C:\Users\皮卡丘\AppData\Roaming\Typora\typora-user-images\image-20210118175110731.png)]

  • login.jsx
import React,{Component} from 'react'
import './index.scss'
import logo from '../../assets/logo.svg'
import {Card, Form, Input, Button, Checkbox, message} from "antd";
import { UserOutlined, LockOutlined } from '@ant-design/icons';
import {logins} from '../../Store/Actions'
import {connect} from 'react-redux'
class Login extends Component{
    onFinish = async (values) => {
        let data =this.props.loginRes
        let temp = {}
        data.forEach(el=>{
            if(el.name===values.username){
                temp=el
            }
        })
       if(temp.name===values.username && temp.password===values.password){
           message.success('登录成功')
           window.location.pathname='/home'
       }else {
          message.error('用户名或者密码不正确')
       }
    }
    componentDidMount() {
        this.props.login()
    }
    render() {
        return(
            <div className={'login'}>
                <Card className={'loginBox'}>
                    <img src={logo}/>
                    <Form
                        name="normal_login"
                        className="login-form"
                        initialValues={{
                            remember: true,
                            username:'admin',
                            password:'123456'
                        }}
                        onFinish={this.onFinish}
                    >
                        <Form.Item
                            name="username"
                            rules={[
                                {
                                    required: true,
                                    message: '请输入账号名称!',
                                },
                            ]}
                        >
                            <Input prefix={<UserOutlined className="site-form-item-icon" />} placeholder="账号" />
                        </Form.Item>
                        <Form.Item
                            name="password"
                            rules={[
                                {
                                    required: true,
                                    message: '请输入账号密码!',
                                },
                            ]}
                        >
                            <Input
                                prefix={<LockOutlined className="site-form-item-icon" />}
                                type="password"
                                placeholder="密码"
                            />
                        </Form.Item>
                        <Form.Item>
                            <Form.Item name="remember" valuePropName="checked" noStyle>
                                <Checkbox>自动登录</Checkbox>
                            </Form.Item>
                        </Form.Item>
                        <Form.Item>
                            <Button  style={{width:'100%',borderRadius:'6px'}} type="primary" htmlType="submit" className="login-form-button">
                               登录
                            </Button>
                        </Form.Item>
                    </Form>
                </Card>
            </div>
        )
    }
}
const mapProps = state =>{
    return({
        count:state.count,
        loginRes:state.loginRes
    })
}
const  mapActions = dispatch =>{
    return{
        login(){
            dispatch(logins())
        }
    }
}
export default connect(mapProps,mapActions)(Login)

  • app.js
import React,{Component} from 'react'
import './App.css'
import {BrowserRouter as Router,Route} from 'react-router-dom'
import {Login,Home} from './Components'
class APP extends Component{
    render() {
        return (
            <Router>
                <div className={'app'}>
                    <Route path={'/'} component={Login} exact/>
                    <Route path={'/login'} component={Login} />
                    <Route path={'/home'} component={Home} />
                </div>
            </Router>
        )
    }
}
export default APP

2.2 首页开发

  • 路由编写

    import React from 'react'
    import {All,Device,Interface,Operation,Setting,Profiles} from '../Pages'
    import {
        DashboardOutlined,
        RocketOutlined,
        SnippetsOutlined,
        FileTextOutlined,
        WifiOutlined,
        SettingOutlined
    } from '@ant-design/icons';
    export const RouterList=[
        {
            id:1,
            name:'概览',
            path:'/index',
            component:All,
            icon:<DashboardOutlined />
        },
        {
            id:2,
            name:'设备',
            path:'/device',
            component:Device,
            icon:<RocketOutlined />
        },
        {
            id:3,
            name:'设备Profiles',
            path:'/profiles',
            component:Profiles,
            icon:<SnippetsOutlined />
        },
        {
            id:4,
            name:'操作日志',
            path:'/operation',
            component:Operation,
            icon:<FileTextOutlined />
        },
        {
            id:5,
            name:'数据接口',
            path:'/data',
            component:Interface,
            icon:<WifiOutlined />
        },
        {
            id:6,
            name:'设置',
            path:'/setting',
            component:Setting,
            icon:<SettingOutlined />
        },
    ]
    
    
  • 首页开发

    import React,{Component} from "react";
    import { Layout, Menu } from 'antd';
    import {
        MenuUnfoldOutlined,
        MenuFoldOutlined,
    } from '@ant-design/icons';
    import './index.scss'
    import {RouterList} from '../../Routers'
    import {HashRouter as Router, Route, Link, Redirect} from 'react-router-dom'
    const { Header, Sider, Content } = Layout;
    export default class Home extends Component{
        constructor() {
            super();
            this.state={
                collapsed: false
            }
    
        }
        toggle = () => {
            this.setState({
                collapsed: !this.state.collapsed,
            });
        };
        render() {
            return(
             <Router>
                 <div className={'layout'}>
                     <Layout>
                         <Sider trigger={null} collapsible collapsed={this.state.collapsed}>
                             <div className="logo" />
                             <Menu theme="dark" mode="inline" defaultSelectedKeys={['1']} style={{height:'90vh'}}>
                                 {
                                     RouterList.map((el,index)=>{
                                         return(
                                             <Menu.Item key={el.id} icon={el.icon}>
                                                 <Link to={el.path}>{el.name}</Link>
                                             </Menu.Item>
                                         )
                                     })
                                 }
                             </Menu>
                         </Sider>
                         <Layout className="site-layout">
                             <Header className="site-layout-background" style={{ padding: 0,color:'#fff',backgroundColor:'#001529',height:'68px' }}>
                                 {React.createElement(this.state.collapsed ? MenuUnfoldOutlined : MenuFoldOutlined, {
                                     className: 'trigger',
                                     onClick: this.toggle,
                                 })}
                             </Header>
                             <Content
                                 className="site-layout-background"
                                 style={{
                                     margin: '24px 16px',
                                     padding: 24,
                                     minHeight: '80vh',
                                 }}
                             >
                                 {/*<Redirect to={'/'}  />*/}
                                 {
                                     RouterList.map((el,index)=>{
                                         return(
                                             <Route path={el.path} component={el.component} key={el.id}/>
                                         )
                                     })
                                 }
                             </Content>
                         </Layout>
                     </Layout>
                 </div>
             </Router>
            )
        }
    }
    
    

2.3 模块开发

1 数据接口
2 首页
  • 使用图表

    cnpm install echarts --save

  • 按时间查询

    cnpm install moment -S

2.4 表格数据导出

  • 下载依赖cnpm i react-html-table-to-excel -S
<div>
                        <Table columns={this.state.columns} dataSource={this.state.data} pagination/>
                        <table ref="table" id='table-to-xls' style={{display:"none"}}>
                            <tr>
                                <th>ID</th>
                                <th>Name</th>
                            </tr>
                            {
                                this.state.dataNone.map((el,index)=>{
                                    return (
                                        <tr>
                                            <td>{index+1}</td>
                                            <td>{el}</td>
                                        </tr>
                                    )
                                })
                            }
                        </table>

                    </div>
  • 导出
export=()=>{
        const tableCon = ReactDOM.findDOMNode(this.refs['table'])
        const table = tableCon.querySelector('table')
        // table.setAttribute('id', 'table-to-xls')

        console.log(table)
    }

3 跨域错误

  • const proxy = require('http-proxy-middleware')
    module.exports = function(app) {
        app.use(
            proxy.createProxyMiddleware('/api', { //`api`是需要转发的请求
                target: 'http://172.30.195.14:8639', // 这里是接口服务器地址
                changeOrigin: true,
                pathRewrite: {'^/api':'/'}
            })
        )
    }
    
  • cnpm i cross-env  http-proxy-middleware  -S
    
  • "start": "cross-env PORT=8639 react-scripts start",
    
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值