1、谷粒后台开发准备及登录页面
开发准备
代码仓库:https://github.com/changeclass/react-admin/commits/
技术选型
前端路由
创建项目
基于脚手架创建项目
1
create-react-app react-admin_client
编辑基本结构
入口文件
1
2
3
4
5
6
7
8
9
10
11
12/**
* 入口文件
*/
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<App />,
document.getElementById('root')
);根组件
1
2
3
4
5
6
7
8
9
10
11/**
* 应用根组件
*/
import React, { Component } from "react";
export default class App extends Component {
render () {
return <div>ahha </div>
}
}其他目录结构
引入AntD
安装插件
1
2
3yarn add antd
# 实现组件按需打包的依赖
yarn add react-app-rewired customize-cra babel-plugin-import配置按需打包,在根目录创建
config-overrides.js
文件。1
2
3
4
5
6
7
8const {override, fixBabelImports} = require('customize-cra');
module.exports = override(
fixBabelImports('import', {
libraryName: 'antd',
libraryDirectory: 'es',
style: 'css',
}),
);修改
package.json
文件1
2
3
4
5
6"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-scripts eject"
},自定义主题
安装
1
yarn add less less-loader
修改
config-overrides.js
文件1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16const { override, fixBabelImports, addLessLoader } = require('customize-cra');
module.exports = override(
fixBabelImports('import', {
libraryName: 'antd',
libraryDirectory: 'es',
style: true,
}),
addLessLoader({
lessOptions: {
javascriptEnabled: true,
modifyVars: {
'@primary-color': '#2daebf'
}
}
})
);引入路由
安装插件
1
yarn add react-router-dom
入口文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17import { BrowserRouter, Route, Switch } from 'react-router-dom'
import Admin from './pages/admin/admin';
import Login from './pages/login/login';
export default class App extends Component {
render () {
return (
<BrowserRouter>
<Switch>
<Route path='/login' component={Login}></Route>
<Route path='/' component={Admin}></Route>
</Switch>
</BrowserRouter>
)
}
}子组件
1
2
3
4
5
6
7
8
9
10/**
* 管理的路由组件
*/
import React, { Component } from 'react'
export default class Admin extends Component {
render() {
return <div>Admin</div>
}
}
登录页面-布局
代码仓库:https://github.com/changeclass/react-admin/commits/dev
HTML结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16export default class Login extends Component {
render () {
return (
<div className='login'>
<header className='login-header'>
<img src={logo} />
<h1>React项目:谷粒商城</h1>
</header>
<section className='login-content'>
<h2>用户登录</h2>
<div>Form组件标签</div>
</section>
</div>
)
}
}login的样式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34// login组件样式
.login {
width: 100%;
height: 100%;
background-image: url('./images/bg.jpg');
background-size: 100% 100%;
.login-header {
display: flex;
align-items: center;
height: 80px;
background-color: rgba(21, 20, 13, 0.5);
img {
width: 40px;
height: 40px;
margin: 0 15px 0 50px;
}
h1 {
font-size: 30px;
color: white;
}
}
.login-content {
width: 400px;
height: 300px;
background-color: #fff;
margin: 50px auto;
padding: 20px 40px;
h2 {
text-align: center;
font-size: 30px;
font-weight: bolder;
}
}
}全局样式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92html,
body,
p,
ol,
ul,
li,
dl,
dt,
dd,
blockquote,
figure,
fieldset,
legend,
textarea,
pre,
iframe,
hr,
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0;
padding: 0;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-size: 100%;
font-weight: normal;
}
ul {
list-style: none;
}
button,
input,
select,
textarea {
margin: 0;
}
html {
box-sizing: border-box;
}
*,
*::before,
*::after {
box-sizing: inherit;
}
img,
video {
height: auto;
max-width: 100%;
}
iframe {
border: 0;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
td,
th {
padding: 0;
}
td:not([align]),
th:not([align]) {
text-align: left;
}
html,
body {
height: 100%;
width: 100%;
}
#root {
height: 100%;
width: 100%;
}
登录页面-Form表单
1 | import { Form, Input, Button, Checkbox } from 'antd' |
登录页面-表单收集
视频中使用了AntD3的获取方式,然而AntD4与3版本获取表单实例略有差异。
获取表单实例
为
Form
组件添加属性ref
,在类通过React.createRef
创建表单引用。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
export default class Login extends Component {
// 创建表单实例
formRef = React.createRef()
// 表单提交事件
handleSubmit = () => {
console.log(this.formRef)
}
render() {
return (
<div className='login'>
<header className='login-header'>
<img src={logo} />
<h1>React项目:谷粒商城</h1>
</header>
<section className='login-content'>
<h2>用户登录</h2>
<Form
name='normal_login'
className='login-form'
// 为表单添加引用
ref={this.formRef}
// 为表单添加校检完成的事件
onFinish={this.handleSubmit}
>
</Form>
</section>
</div>
)
}
}
完整代码
1 | import React, { Component } from 'react' |
登录页面-Form的验证方式
声明式验证
1
2
3
4
5
6
7
8
9
10
11
12
13
14<Form.Item
name='username'
// 声明式验证
rules={[
{ required: true, whitespace: true, message: '请输入用户名' },
{ min: 4, message: '用户名最少4位' },
{ max: 12, message: '用户名最多12位' },
{
pattern: /^[a-zA-Z0-9_]+$/,
message: '用户名必须是大写字母、小写字母或下划线组成'
}
]}
>
</Form.Item>自定义验证
1
2
3
4<Form.Item
name='password'
rules={[{ validator: this.validatePwd }]}
></Form.Item>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17// 自定义验证-密码
// AntD4中已经没有callback回调函数了,而是返回Promise对象
validatePwd = (rule, value) => {
// value 表示当前输入框传入的值
console.log(rule, value)
if (!value) {
return Promise.reject('密码必须输入')
} else if (value.length < 5) {
return Promise.reject('密码长度不能小于4')
} else if (value.length > 12) {
return Promise.reject('密码长度不能大于12')
} else if (!/^[a-zA-Z0-9_]+$/.test(value)) {
return Promise.reject('密码必须是大写字母、小写字母或下划线组成')
} else {
return Promise.resolve()
}
}
登录页面-Form的统一验证
新版直接使用 onFinish
事件,该事件仅当校验通过后才会执行。
1 | <Form.Item |
1 | // 自定义验证-密码 |
发送Ajax请求
安装axios插件
1
yarn add axios
在
api/ajax.js
文件中封装ajax请求,并处理错误请求1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29/**
* 发送异步请求的模块
* 1. 统一处理请求异常
*/
import axios from 'axios'
import { message } from 'antd'
export default function ajax (url, data = {}, method = 'GET') {
return new Promise((resolve, reject) => {
let promise
// 1. 执行异步请求
if (method === 'GET') {
promise = axios.get(url, {
params: data
})
} else {
promise = axios.post(url, data)
}
promise
.then(response => {
// 2. 成功调用resolve
resolve(response)
})
.catch(error => {
// 3. 失败不调用reject,而是提示异常信息
message.error("请求出错了:" + error.message);
})
})
};封装接口请求函数
为了方便请求接口,将请求的重心放在数据传输上,而将各种接口封装成一个函数,只需要向此函数传递参数即可。
1
2
3
4
5
6
7
8
9/**
* 包含应用中所有接口请求的函数的模块
* 每个函数的返回值都是Promise
*/
import ajax from './ajax'
// 登录
export const reqLogin = (username, password) => ajax('/login', { username, password }, "POST")
// 添加用户
export const reqAddUser = (user) => ajax('/manage/user/add', user, "POST")跨域问题
使用脚手架创建的项目只需要在
package.json
文件中加入代理字段即可。1
2
3{
"proxy":"http://127.0.0.1:5000"
}数据持久化
登录时
将数据保存到local中,并同时放入内存中。
进入登录页面时
获取内存中是否有登录字段,如果有则重定向管理页面
进入页面
一进入页面将local中的用户数据存储到内存中。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 小康博客!
评论
TwikooWaline