前端:React+React-router+Redux+ant
创建项目完成图示.png
然后我们进入项目并启动:
cd antd-demo-ts //进入项目
npm start //启动应用
此时浏览器会访问 http://localhost:3000/ ,看到 Welcome to React
的界面就算成功了。
二、测试ant Desgin引用是否成功
cnpm install antd --save-dev //使用cnpm安装ant design依赖并写入package.json文件中
安装成功后,我们先修改 src/App.tsx
文件
import * as React from 'react';
import Button from 'antd/lib/button';
import './App.css';
import logo from './logo.svg';
class App extends React.Component {
public render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<p className="App-intro">
To get started, edit <code>src/App.tsx</code> and save to reload.
</p>
<Button type="primary">AntDesgin按钮</Button>
</div>
);
}
}
export default App;
然后修改 src/App.css
引入 antd 的样式:
@import '~antd/dist/antd.css'; //在App.css文件顶部引入
.App {
text-align: center;
}
...
修改完成后 npm start
启动项目查看效果。。
本菜当时看到这个问题的时候也是一脸懵逼,什么情况呢?上网找答案之后发现原来是ts校验规则的问题,这点我实在非常想要吐槽,import引入居然要按照字母排序,十分不适应,后续还会有更多的ts校验规则的问题,在此就先解决再继续往下进行。
修改项目根目录下 tslint.json
文件
{
"extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"],
"linterOptions": {
"exclude": [
"config/**/*.js",
"node_modules/**/*.ts"
]
},
"rules": {
"ordered-imports": false,
"prefer-const": false,
"no-console":false,
"no-debugger":false,
"await-promise":false,
"curly":false,
"no-empty":false,
"no-for-in-array":false,
"no-invalid-this":false,
"no-var-keyword":false,
"member-access": false,
"max-classes-per-file":false,
"prefer-for-of":false,
"triple-equals":false,
"no-unused-expression": false,
"prefer-readonly": false,
"comment-format":false,
"no-unnecessary-initializer": false,
"no-unused-variable": false,
"object-literal-sort-keys": false,
"no-string-literal": false,
"no-default-export":false
}
}
将 tslint.json文件内容替换为上述代码即可解决问题,规则解释如下(官方文档 https://palantir.github.io/tslint/rules/ ,参考文档 https://www.cnblogs.com/wyy5552/p/8796695.html):
以上解决了ts校验规则的问题后,重新运行项目发现编译成功,运行效果图如下:
此时我们成功引用进来了
ant Desgin
!三、实际项目中的ant design按需引入的性能优化 run.png
至此我们对
ant Design
的引入就告一段落了。注:以上参考ant design官方文档
https://ant.design/docs/react/use-in-typescript-cn
四、修改项目目录
按照个人习惯,我们新建assets文件夹以便于管理,修改后项目目录如下图所示:
注:修改完成后,别忘记修改 App.tsx、index.tsx 文件中的import路径哦
五、引入scss
由于本菜喜欢scss的书写方便,由此引入,习惯css的同学可以不使用
1、安装 sass-loader
node-sass
依赖:
cnpm install add sass-loader node-sass --save-dev //安装 sass-loader node-sass 依赖
path.png
好了,通过上述步骤我们找到了webpack的配置文件,其实我们通过
package.json
中的start
命令可以发现点端倪,其实webpack只是被封装起来了,接下来我们就修改
webpack.config.dev.js
文件:
{
test: /\.css$/,
use: [
...
],
},
{
test: /\.scss$/,
loaders: ['style-loader', 'css-loader', 'sass-loader'],
}, //增加scss的规则
修改完成之后我们在 assets
文件夹下创建新的 scss
文件夹,并手动创建 App.scss
文件及 index.scss
文件:
创建完成后将 App.css
及 index.scss
文件中的代码直接复制进对应的scss
文件,然后删除css
文件夹,操作完成后的项目目录如下:
上述修改完成后,重启项目发现
scss
成功引入!
六、创建Spring-Boot项目并整合Mybatis
本菜在此就不做详细赘述了,想必用java的同学都会,不会的话参考下面链接:
1、spring-boot 1.5.*版本项目搭建及整合mybatis (https://blog.csdn.net/winter_chen001/article/details/77249029)
2、spring-boot 2.0+版本项目搭建及整合mybatis (https://blog.csdn.net/Winter_chen001/article/details/80010967)
七、编写登录所需接口
代码如下(仅贴出controller
层~):
package com.ycgame.controller;
import com.ycgame.model.Result;
import com.ycgame.model.User;
import com.ycgame.service.user.UserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.List;
import static com.ycgame.utils.SetResultInfo.setResultInfo;
/**
* Created by Administrator on 2018/7/16.
*/
@Controller
@RequestMapping(value = "/user")
public class UserController {
@Autowired
private UserService userService;
@ResponseBody
@PostMapping("/login")
public Result login(@RequestBody User user, HttpServletRequest request){
System.out.println(user.getUsername());
Result result=userService.findByUsername(user);
if(result.getCode()==0){
HttpSession session=request.getSession();
session.setAttribute("user",user);
}
return result;
}
@ResponseBody
@GetMapping("/loginState")
public Result loginState(HttpServletRequest request){
HttpSession session=request.getSession();
User user=(User)session.getAttribute("user");
Result result;
if(user!=null){
List<Object> dataList=new ArrayList<Object>();
dataList.add(user);
result=setResultInfo(0,dataList,"已登录");
}else{
result=setResultInfo(103,null,"未登录");
}
return result;
}
@ResponseBody
@GetMapping("/loginOut")
public Result loginOut(HttpServletRequest request){
HttpSession session=request.getSession();
session.removeAttribute("user");
Result result=setResultInfo(0,null,null);
return result;
}
}
上述接口功能分别为:登录
、获取登录状态
、退出登录
八、引入React-router及axios
安装 react-router
依赖,本菜使用的是V4版本,各位可自行选择
cnpm install react-router-dom --save-dev //cnpm安装react-router-dom(react-router V4版本)
cnpm install @types/react-router-dom --save-dev
为了实现类似 vue-router
中编程式导航的功能,本菜参考(https://segmentfault.com/a/1190000011137828)的第三种方案(主要刚接触,第一种方法不太会。。而且貌似挺麻烦。。勿喷。。)
1、安装history依赖
cnpm install @types/history --save-dev //安装histroy依赖
2、自己创建一个 history.ts/.js
文件,文件类型和位置看个人喜好,代码如下:
import createHistory from 'history/createBrowserHistory';
export default createHistory();
经过以上步骤,我们的 react-router
就算成功引入了。下面开始引入axios
cnpm install axios --save-dev //安装axios
安装完成后,本菜对axios发送请求做了简单的封装(utils.ts
),代码如下:
//utils.ts
import axios from 'axios'
const utils ={
axiosMethod: (config:any) => {
axios({
method: config.method,
url: config.url,
params: config.params ? config.params : null,
data: config.data ? config.data : null,
}).then(config.callback).catch(config.catch ? config.catch : () => {})
}
}
export default utils
本菜为了请求统一管理新建了一个 axiosRequestConfig.ts
文件,代码如下:
//axiosRequestConfig.ts
const config={
//登录校验
doLoginConfig:{
method:'post',
url:'/user/login'
},
//登录状态验证
loginStateConfig:{
method:'get',
url:'/user/loginState'
},
//退出登录
loginOutConfig:{
method:'get',
url:'/user/loginOut'
}
}
export default config
经过上述步骤,我们成功引入了react-router
及axios
,本菜当前的项目目录如下:
九、配置webpack代理
由于spring-boot运行在8080端口,而我们的react项目则是3000端口,因此存在跨域问题,那么我们如何配置webpack的代理呢,下面上代码:
首先按照 第五步
的方法找到 webpackDevServer.config.js
文件(node_modules =>react-scripts-ts =>config=>webpackDevServer.config.js
),修改为以下内容:
...
https: protocol === 'https',
host: host,
overlay: true,
historyApiFallback: {
// Paths with dots should still use the history fallback.
// See https://github.com/facebookincubator/create-react-app/issues/387.
disableDotRule: true,
},
public: allowedHost,
proxy: {
'/user/*': {
target: 'http://localhost:8080/', //本地后台的地址
secure: false,
changeOrigin: true
},
},
before(app){
...
经过上述步骤,我们就能放心的撸代码了,再也不用担心跨域请求的问题啦~~
十、开始撸码
1、新建 Login.tsx
文件,文件位置看个人习惯,本菜直接放在src下面,使用ant design表单组件,代码如下:
//Login.tsx
import * as React from 'react';
import './assets/scss/Login.scss';
import utils from './utils/utils'
import requestConfig from './utils/axiosRequestConfig'
import { Form, Icon, Input, Button, Checkbox } from 'antd';
import history from './utils/history';
const FormItem = Form.Item;
class LoginForm extends React.Component {
constructor(props: any) {
super(props);
this.state = {
loginForm: {
username: '',
password: ''
}
}
this.handleInputChange = this.handleInputChange.bind(this);
this.submitForm = this.submitForm.bind(this);
}
handleInputChange(event: any): void {
const target = event.target;
const value = target.value;
const name = target.name;
const tempObj = { ...this.state['loginForm'] };
tempObj[name] = value;
this.setState({
loginForm: tempObj
})
}
submitForm(e: any) {
e.preventDefault();
this.props['form'].validateFields((err: any, values: any) => {
if (!err) {
let doLoginConfig = requestConfig.doLoginConfig;
let config = {
data: { t: new Date().getTime(), ...this.state['loginForm'] },
callback: (response: any) => {
if (response.data.code == 0) {
history.push('/home');
}
}
}
let finalConfig = { ...doLoginConfig, ...config };
utils.axiosMethod(finalConfig);
}
});
}
render(): any {
const { getFieldDecorator } = this.props['form'];
return (
<Form onSubmit={this.submitForm} className="login-form">
<FormItem>
{getFieldDecorator('userName', {
rules: [{ required: true, message: '请输入用户名', whitespace: true }],
})(
<Input name='username' onChange={this.handleInputChange} prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />} placeholder="请输入用户名" />
)}
</FormItem>
<FormItem>
{getFieldDecorator('password', {
rules: [{ required: true, message: '请输入密码', whitespace: true }],
})(
<Input name='password' onChange={this.handleInputChange} prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />} type="password" placeholder="请输入密码" />
)}
</FormItem>
<FormItem>
{getFieldDecorator('remember', {
valuePropName: 'checked',
initialValue: true,
})(
<Checkbox style={{ color: 'white' }}>记住我</Checkbox>
)}
<a className="login-form-forgot" href="">忘记密码</a>
<Button type="primary" htmlType="submit" className="login-form-button">
登录
</Button>
<a href="">前往注册</a>
</FormItem>
</Form>
);
}
}
const LoginFormComponent = Form.create()(LoginForm);
class Login extends React.Component {
render() {
return (
<div className="loginMain">
<div className="login">
<h2 style={{ color: 'white', textAlign: 'center' }}>用户登录</h2>
<LoginFormComponent />
</div>
</div>
);
}
}
export default Login;
2、在assets/scss
文件夹下新建 Login.scss
的样式文件,代码如下:
//Login.scss
h2 {
font-size: 20px;
}
.loginMain{
height: 100%;
background: url('../images/bg.jpg') no-repeat center center fixed;
background-size: cover;
}
.login{
width:350px;
height:330px;
background: rgba($color: #000, $alpha: .4);
border-radius: 20px;
margin: auto;
padding: 25px;
color: white;
position: absolute;
left: 0 ;
right: 0;
top:25%;
}
.login-form {
max-width: 300px;
}
.login-form-forgot {
float: right;
}
.login-form-button {
width: 100%;
}
3、修改 index.tsx
文件,代码如下:
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import App from './App';
import Login from './Login';
import registerServiceWorker from './registerServiceWorker';
import { Router, Route } from 'react-router-dom';
import history from './utils/history';
import requestConfig from './utils/axiosRequestConfig'
import utils from './utils/utils'
import './assets/scss/index.scss';
class Model extends React.Component {
constructor(props: any) {
super(props);
}
componentDidMount() {
const loginStateConfig = requestConfig.loginStateConfig;
const config = {
param: { t: new Date().getTime() },
callback: (response: any) => {
if (response.data.code == 0) {
history.push('/home');
} else {
history.push('/');
}
}
}
const finalConfig = { ...loginStateConfig, ...config };
utils.axiosMethod(finalConfig);
}
render() {
return (
<div style={{ height: '100%' }}>
<Route exact={true} path="/" component={Login} />
<Route exact={true} path="/home" component={App} />
</div>
)
}
}
ReactDOM.render(
<Router history={history}>
<Model />
</Router>
,document.getElementById('root') as HTMLElement
);
registerServiceWorker();
4、给 App.tsx
增加退出登录按钮,修改后代码如下:
import './assets/scss/App.scss';
import * as React from 'react';
import history from './utils/history';
import requestConfig from './utils/axiosRequestConfig'
import utils from './utils/utils'
import { Button, Icon } from 'antd';
import logo from './assets/images/logo.svg';
class App extends React.Component {
constructor(props: any) {
super(props);
this.loginOutMethod = this.loginOutMethod.bind(this);
}
loginOutMethod() {
const loginOutConfig = requestConfig.loginOutConfig;
const config = {
param: { t: new Date().getTime() },
callback: (response: any) => {
if (response.data.code == 0) {
history.push('/');
}
}
}
const finalConfig = { ...loginOutConfig, ...config };
utils.axiosMethod(finalConfig);
}
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<p className="App-intro">
To get started, edit <code>src/App.tsx</code> and save to reload.
</p>
<Button type="primary">AntDesgin按钮</Button>
<Icon style={{ color: 'green', fontSize: '24px', marginLeft: '50px' }} type="check-circle-o" />
<br/>
<Button style={{marginTop:'30px'}} onClick={this.loginOutMethod}>退出登录</Button>
</div>
);
}
}
export default App;
以上我们的代码部分就暂时撸完了现在我们启动spring-boot
项目及npm start
运行react项目,效果如下(不会做gif理解一下。。。):
image.png
输入正确的用户名密码后点击登录会跳转到
localhost:3000/home
页面(主页),点击退出登录会返回登录页测试效果与我们希望的结果一致。
结束语
看到这里就结束了!!?这时候就会有小伙伴说了,Redux被你吃了么?全程没看到啊。。说来惭愧,Redux整合本菜倒是弄得差不多了,然而由于刚接触,后续有空再更新吧。。
以上就是本菜最近几天的摸索成果,实现起来可能不够优雅,希望各位React大佬勿喷,毕竟我只是一个React的萌新。。。最后希望本文对各位同学入坑React能有所帮助,如果能帮到您,是我的荣幸~~