项目包以下
连接:https://pan.baidu.com/s/1C-ZY9rWU-8ZugE4EwVveWw
提取码:744pcss
相关react介绍连接以下
http://www.javashuo.com/article/p-egypmnww-h.htmlhtml解压并修改目录为blog 没有特殊说明,js 文件均放置在src目录中前端
本环境后端服务ip地址为192.168.1.200,后端python监听端口为80.node
npm i
启动并查看python
npm start
本次使用react-router 进行路由配置工做
基础例子 react
https://reacttraining.com/react-router/web/example/basic
官方文档ios
https://reacttraining.com/react-router/web/guides/quick-start
根据官方示例,修改src/index.js以下git
import React from 'react'; import ReactDom from 'react-dom'; import { BrowserRouter as Router, Route, Link } from "react-router-dom"; const Home =() => { return ( <div> <h2>Home</h2> </div> ); } const About=() => { return ( <div> <h2>About</h2> </div> ); } class Root extends React.Component { render() { return ( <Router> <div> <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> </div> </Router> ) } } ReactDom.render(<Root />,document.getElementById('root'));
显示结果以下github
Route 负责静态路由
path 是匹配的路径,没有path老是匹配。
component 是目标组件。
exact: 布尔值,true 时要求路径彻底匹配。
strict: 布尔值,true 时要求严格匹配,可是url字符串能够是本身的字串。web地址变化,Router组件会匹配路径,而后使用匹配的组件进行渲染
添加css目录,并建立全局CSS文件login.css
body { background: #456; font-family: SimSun; font-size: 14px; } .login-page{ width: 360px; padding: 8% 0 0; margin: auto; } .form { font-family: "Microsoft YaHei",SimSun; position: relative; z-index:1; background: #ffffff; max-width: 360px; margin: 0 auto 100px; padding: 45px; text-align: center; box-shadow: 0 0 20px 0 rgba(0,0,0,0.2), 0 5px 5px 0 rgba(0,0,0,0.24); } .form input{ outline: 0; background: #f2f2f2; width: 100%; border: 0; margin: 0 0 15px; padding: 15px; box-sizing: border-box; font-size: 14px; } .form button{ text-transform: uppercase; outline: 0; background: #4cAf50; width: 100%; border: 0; padding: 15px; color: #ffffff; font-size: 14px; cursor: pointer; } .form button:hover,.from button.active,.form button.focus { background: #43a047; } .from .message{ margin: 15px 0 0; color: #bb33bb; font-size: 12px; } .form .message a{ color: #4caf50; text-decoration: none; }
以下
在component 目录下构建react组件
登陆模板
https://codepen.io/colorlib/pen/rxddKy?q=login&limit=all&type=type-pens
添加component目录,其在src下
HTML版登陆模板以下
<div class="login-page"> <div class="form"> <form class="register-form"> <input type="text" placeholder="name"/> <input type="password" placeholder="password"/> <input type="text" placeholder="email address"/> <button>create</button> <p class="message">Already registered? <a href="#">Sign In</a></p> </form> <form class="login-form"> <input type="text" placeholder="username"/> <input type="password" placeholder="password"/> <button>login</button> <p class="message">Not registered? <a href="#">Create an account</a></p> </form> </div> </div>
使用此HTML模板来进行构建组件
注意:
搬到React组件中的时候,要将class 属性修改成ClassName
全部标签,必须闭合
login.js 建立
在 component 目录下建立login.js登陆组件
使用上面的HTML模板中的登陆部分,挪到render函数中。
以下
import React from 'react'; import {Link} from 'react-router-dom'; export default class Login extends React.Component{ render(){ return ( <div className="login-page"> <div className="form"> <form className="register-form"> <input type="text" placeholder="邮箱"/> <input type="password" placeholder="密码"/> <button>登陆</button> {/*触发按钮*/} <p className="message">还未注册 <Link to="/reg">请注册</Link></p> </form> </div> </div> ) } }
index.js 中添加路由以下
import React from 'react'; import ReactDom from 'react-dom'; import { BrowserRouter as Router, Route, Link } from "react-router-dom"; import Login from './component/login' //引入对象 const Home =() => { return ( <div> <h2>Home</h2> </div> ); } const About=() => { return ( <div> <h2>About</h2> </div> ); } class Root extends React.Component { render() { return ( <Router> <div> <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> <Route path="/login" component={Login} /> {/*此处主要是跳转至login对象*/} </div> </Router> ) } } ReactDom.render(<Root />,document.getElementById('root'));
结果以下
导入样式表以下
import React from 'react'; import '../css/login.css' import {Link} from 'react-router-dom'; export default class Login extends React.Component{ render(){ return ( <div className="login-page"> <div className="form"> <form className="register-form"> <input type="text" placeholder="邮箱"/> <input type="password" placeholder="密码"/> <button onClick={event =>console.log(event)}>登陆</button> {/*触发按钮*/} <p className="message">还未注册 <Link to="/reg">请注册</Link></p> </form> </div> </div> ) } }
结果以下
页面中默认传递的数据是from data
在src/component/login.js中定义handlerClick函数用于获取触发事件生成的数据
上述的每一次填写会致使页面的刷新,而不是等到点击提交后才刷新,要阻止页面刷新,其实就是要阻止提交,可以使用event.preventDefault()来阻止页面的自动提交如何拿到邮箱和密码
event.target.from 返回按钮所在的表单,可看作一个数组
fm[0].value和fm[1].value就是文本框的值
在login组件中使用UserServie实例的方法:
1 在Login构造器中直接进行初始化
2 在props中传入
相关代码以下
import React from 'react'; import '../css/login.css' import {Link} from 'react-router-dom'; export default class Login extends React.Component{ handlerClick(event){ event.preventDefault(); //其默认是写一条数据提交一次,此命令用于阻止其默认提交 console.log('邮箱',event.target.form[0].value) // 此处用于获取相关用户登陆信息, console.log('密码',event.target.form[1].value) } render(){ return ( <div className="login-page"> <div className="form"> <form className="register-form"> <input type="text" placeholder="邮箱"/> <input type="password" placeholder="密码"/> <button onClick={this.handlerClick.bind(this)}>登陆</button> {/*触发按钮*/} <p className="message">还未注册 <Link to="/reg">请注册</Link></p> </form> </div> </div> ) } }
结果以下
经过上述的event.target.form[1].value可获取到表单提交的数据
在component中建立reg.js用于注册函数
import React from 'react'; import '../css/login.css' import {Link} from 'react-router-dom'; import UserService from '../service/user' const service= new UserService(); export default class Reg extends React.Component{ render(){ return <_Reg server={service} />; {/*经过此处将service传递下去,后期能够经过props.service.xxx方法来完成数据的注入操做*/} } } class _Reg extends React.Component { handleClick(event) { event.preventDefault(); //处理页面刷新问题,阻止缺省行为 let fm=event.target.form; console.log(fm[0].value,fm[1].value,fm[2].value,fm[3].value) //获取注册信息 } render() { console.log('++++++++++++++++++++++++') return ( <div className="login-page"> <div className="form"> <form className="register-form"> <input type="text" placeholder="姓名" /> <input type="text" placeholder="邮箱" /> <input type="password" placeholder="密码" /> <input type="password" placeholder="确认密码" /> <button onClick={this.handleClick.bind(this)}>注册</button> <p className="message">若是已注册 <Link to="login">请登录</Link></p> {/*此处用于跳转*/} </form> </div> </div> ) } }
添加路由
import React from 'react'; import ReactDom from 'react-dom'; import { BrowserRouter as Router, Route, Link } from "react-router-dom"; import Login from './component/login'; import Reg from './component/reg'; const Home =() => { return ( <div> <h2>Home</h2> </div> ); } const About=() => { return ( <div> <h2>About</h2> </div> ); } class Root extends React.Component { render() { return ( <Router> <div> <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> <Route path="/login" component={Login} /> <Route path="/reg" component={Reg} /> </div> </Router> ) } } ReactDom.render(<Root />,document.getElementById('root'));
结果以下
上述在表单中填写的内容可在fm[x].value 中直接获取
在index.js中添加导航栏,可方便页面之间的切换
import React from 'react'; import ReactDom from 'react-dom'; import { BrowserRouter as Router, Route, Link } from "react-router-dom"; import Login from './component/login'; import Reg from './component/reg'; const Home =() => { return ( <div> <h2>Home</h2> </div> ); } const About=() => { return ( <div> <h2>About</h2> </div> ); } class Root extends React.Component { render() { return ( <Router> <div> <ul> {/*导航栏相关*/} <li><Link to="/">主页</Link></li> <li><Link to="/about">关于</Link></li> <li><Link to="/reg">注册</Link></li> <li><Link to="/login">登陆</Link></li> </ul> <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> <Route path="/login" component={Login} /> <Route path="/reg" component={Reg} /> </div> </Router> ) } } ReactDom.render(<Root />,document.getElementById('root'));
结果以下
模拟sleep
d1=new Date(); for (var d=new Date();(new Date())-d <1000;);// 此处至关于sleep处理 console.log('------------') d2=new Date(); console.log(d2-d1)
结果以下
登陆代码相关修改
component/login.js
import React from 'react'; import '../css/login.css' import {Link} from 'react-router-dom'; import UserService from '../service/user' export default class Login extends React.Component{ constructor(prpos){ super(prpos); this.service=new UserService; this.state={'ret':-1}; } handlerClick(event){ event.preventDefault(); //其默认是写一条数据提交一次,此命令用于阻止其默认提交 // console.log('邮箱',event.target.form[0].value) // 此处用于获取相关用户登陆信息, // console.log('密码',event.target.form[1].value) console.log('this----------',this) //此处的this指的是Login 实例,可将此值传入进去用于修改ret 的值来触发页面刷新 let fm=event.target.form this.service.login(fm[0].value,fm[1].value,this); //此处用于传输当前login及相关表单数据至后端service层 console.log(this.state.ret) } render(){ if (this.state.ret != -1 ){ // 此处若发生变化,则会致使其状态刷新 console.log('ret',this.state.ret) //打印刷新结果 } return ( <div className="login-page"> <div className="form"> <form className="register-form"> <input type="text" placeholder="邮箱" defaultValue="12345@123"/> <input type="password" placeholder="密码" defaultValue="demo"/> <button onClick={this.handlerClick.bind(this)}>登陆</button> {/*触发按钮*/} <p className="message">还未注册 <Link to="/reg">请注册</Link></p> </form> </div> </div> ) } }
相关代码以下
import axios from 'axios' export default class UserSerive{ login(email,password,obj){ for (var d=new Date();(new Date())-d <10000;);// 此处至关于sleep处理 console.log('12433645645765') console.log(email,password,obj) } }
结果致使浏览器端在进行数据请求时直接停顿,致使其余相关页面也不能刷新或者点开
export default class UserSerive{ login(email,password,obj){ setTimeout(()=> {console.log('timeout---------');obj.setState({'ret':parseInt(Math.random()*100)})}, 10*1000 ) console.log(email,password,'Userservice') } }
此处的结果是其email,password和'Userservice'当即打印,但timeout及后面的打印滞后10s,但在这10s过程当中,其页面是能够进行点击的,及其未阻塞当前业务执行。
obj.setState({'ret':parseInt(Math.random()*100)}) 此处用于生成随机整数
官网代码以下
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
class Root { login(){ new Promise((resolve,reject) => { setTimeout( ()=> { console.log('timeout......') // reject('ok'); resolve('not ok') },5*1000 ) } ).then( value => { console.log('then++++++++++++++++++++++++++') console.log('then-------------------','UserService') }).catch(value => { console.log('then-------------------------') }) console.log('12423423523534564') } } login=new Root(); login.login()
结果以下
export default class UserSerive{ login(email,password,obj){ new Promise((resolve,reject) => setTimeout( () => { console.log('timeout ........'); resolve('ok') //调用此处,将执行then中的代码 },5*1000)).then(value => obj.setState({'ret':parseInt(Math.random()*100)}), console.log('then-------------') ) console.log(email,password,'Userobject') } }
此处的结果是先打印email,password和'Userobject',5秒以后才进行相关的timeout输出和对应的渲染操做,此处因为页面为改变,所以其不会进行DOM渲染。
测试代码以下
class Root { login(){ new Promise((resolve,reject) => { setTimeout( ()=> { console.log('timeout......') reject('ok'); // resolve('not ok') },5*1000 ) } ).then( value => { console.log('then++++++++++++++++++++++++++') console.log('then-------------------','UserService') }).catch(value => { console.log('then-------------------------') }) console.log('12423423523534564') } } login=new Root(); login.login()
结果以下,此处打印的结果是直接输出为12423423523534564,以后在timeout超时后输出then中的内容,此处代表上述的timeout并未阻塞程序自己的运行,此处即是异步调用方式。其不会影响当前请求的下一个数据处理
axios 是一个基于promise的HTTP异步库,能够用在浏览器或nodejs中。
使用axios发起异步调用,完成POST,GET 方法的数据提交,可参照官网例子
http://www.axios-js.com/zh-cn/docs/
安装
npm i axios
导入
import axios from 'axios'
基本实例以下
基本GET 实现
axios.get('/user', { //此处的user是api的url,指定的是绝对路径 params: { //此处表示的是传递的值 ID: 12345 } }) .then(function (response) { //此处表示请求成功的返回值 console.log(response); }) .catch(function (error) { //此处表示失败的返回值 console.log(error); });
基本POST实现
axios.post('/user', { firstName: 'Fred', lastName: 'Flintstone' }) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); });
具体代码以下
import { comparer } from "mobx"; import axios from 'axios' // import { object } from "prop-types"; // import { resolve } from "dns"; //用户逻辑的处理 export default class UserService{ login(email,password,obj) { axios.post('/api/user/login', { 'email': email, 'password': password }) .then(function (response) { //成功执行的操做 console.log(response,'==================='); console.log(response.data) console.log(response.status); obj.setState({'ret':parseInt(Math.random()*100)}) //当返回成功时进行改变状态,进入渲染dom }) .catch(function (error) { //失败执行的操做 console.log(error); }); console.log(email,password,'UserService')// 如何传输,传输什么,返回什么,如何返回的问题 } }
前端页面实现以下
import React from 'react'; import '../css/login.css' import {Link,Redirect} from 'react-router-dom'; import UserService from '../service/user' export default class Login extends React.Component{ constructor(prpos){ super(prpos); this.service=new UserService; this.state={'ret':-1}; } handlerClick(event){ event.preventDefault(); //其默认是写一条数据提交一次,此命令用于阻止其默认提交 // console.log('邮箱',event.target.form[0].value) // 此处用于获取相关用户登陆信息, // console.log('密码',event.target.form[1].value) console.log('this----------',this) //此处的this指的是Login 实例,可将此值传入进去用于修改ret 的值来触发页面刷新 let fm=event.target.form this.service.login(fm[0].value,fm[1].value,this); } render(){ if (this.state.ret !=-1 ) //此处用于判断当不为-1时直接跳转到about页面便可 return <Redirect to='/about' /> return ( <div className="login-page"> <div className="form"> <form className="register-form"> <input type="text" placeholder="邮箱" defaultValue="12345@123"/> <input type="password" placeholder="密码" defaultValue="demo"/> <button onClick={this.handlerClick.bind(this)}>登陆</button> {/*触发按钮*/} <p className="message">还未注册 <Link to="/reg">请注册</Link></p> </form> </div> </div> ) } }
上述中的defaultValue 是为了方便登陆而处理的。
获取数据以下
使用store进行写入客户端的localstorage中,并使用其自带的插件来进行处理过时机制
相关官网
https://github.com/marcuswestin/store.js/
过时插件
相关过时代码以下
https://github.com/marcuswestin/store.js/blob/master/plugins/expire_test.js
添加过时插件和配置
store.addPlugin(require('store/plugins/expire'))
配置过时
store.set('token',response.data.token,(new Date()).getTime()+(8*3600*1000));
一个组件的onClick 触发事件响应函数,此函数会调用后台服务,可是后台服务比较耗时,等处理完成,须要引发组件的渲染操做。
要组件渲染,则须要改变组件的props或state
将index.js进行暂时的修改以下
import React from 'react'; import ReactDom from 'react-dom'; class Service{ handler(e){ console.log('pending..............') for (let d=new Date();new Date() -d < 1000*e;) //此处是同步阻塞模型 console.log('输出') return parseInt(Math.random()*100) } } class Root extends React.Component{ state={'ret':-100} handlerClink(){ this.setState({'ret':this.props.service.handler(10)}) } render(){ return (<div> <button onClick={this.handlerClink.bind(this)}> 点击触发按钮 </button> <span style={{color:'red'}}> {new Date().getTime()} {this.state.ret} </span> </div>) } } ReactDom.render(<Root service={ new Service() }/>,document.getElementById('root'));
结果是过了10秒页面进行刷新,但其在此期间不能点击其余页面
思路一,使用setTimeout
使用setTimeout,有两个问题1 没法向内部的待执行函数传递参数,好比Root实例
2 延时执行的函数返回值复发获取,因此没法通知Root
思路二 promise 异步执行
promise异步执行,若执行成功,则调用回调
import React from 'react'; import ReactDom from 'react-dom'; import { BrowserRouter as Router, Route, Link } from "react-router-dom"; class Service{ handler(obj){ new Promise((resolve,reject)=>{ setTimeout(()=> //此处成功,则返回为此值 resolve('ok') ,5000) }).then(value => { obj.setState({'ret':parseInt(Math.random()*1000)}) }) } } class Root extends React.Component{ state={'ret':-100} handlerClink(){ console.log('触发') this.props.service.handler(this) } render(){ return (<div> <button onClick={this.handlerClink.bind(this)}> 点击触发按钮 </button> <span style={{color:'red'}}> {new Date().getTime()} {this.state.ret} </span> </div>) } } ReactDom.render(<Root service={ new Service() }/>,document.getElementById('root'));
结果以下
上述方式在事件被调用的过程当中,其没有影响到页面的点击,不会阻塞页面的正常处理。
observable装饰器: 设置被观察者
observer 装饰器:设置观察者
import React from 'react'; import ReactDom from 'react-dom'; import { BrowserRouter as Router, Route, Link } from "react-router-dom"; import Login from './component/login'; import Reg from './component/reg'; import {observable} from 'mobx' import {observer} from 'mobx-react' class Service{ @observable ret=-100; handler(){ new Promise((resolve,reject) => { setTimeout(()=>resolve('ok'),5000) }).then((value)=> { this.ret=parseInt(Math.random()*100) }) } } @observer class Root extends React.Component{ handlerClink(){ this.props.service.handler(); } render(){ return <div> <button onClick={this.handlerClink.bind(this)}> 点击触发 </button> <span style={{color:'red'}} > {new Date().getTime()} {this.props.service.ret} </span> </div> } } ReactDom.render(<Root service={new Service() } />,document.getElementById('root'));
其基本结论和上面的相同,其点击不会致使页面问题,实现了异步请求的目的
login登陆触发到about页面以下
src/service/user.js中代码修改以下
import axios from 'axios' import {observable} from 'mobx' import store from 'store' store.addPlugin(require('store/plugins/expire')) //加载过时插件,此处返回一个对象 //用户逻辑的处理 export default class UserService{ @observable loggin=0; // 被观察对象,已经被观察了,一旦值发生变化,则观察者就知道了 login(email,password) { axios.post('/api/user/login', { 'email': email, 'password': password }) .then( (response) => { //成功执行的操做 this的问题经过箭头函数解决 console.log(response,'==================='); console.log(response.data) console.log(response.status); // obj.setState({ret:1000}) //state触发致使改变 store.set('token',response.data.token,(new Date()).getTime()+(8*3600*1000));//getTime拿到的是时间,但其是毫秒 this.loggin = Math.random() * 100; // 修改值 console.log(this.loggin) }) .catch( (error) => { //失败执行的操做 console.log(error); }); //for (var d=new Date();(new Date())-d < 10*1000;); // 此处是同步处理 console.log(email,password,'UserService')// 如何传输,传输什么,返回什么,如何返回的问题 } }
src/component/login.js 结果以下
import React from 'react'; import '../css/login.css' import {Link,Redirect} from 'react-router-dom'; import UserService from '../service/user' import {observer} from 'mobx-react' let service = new UserService() export default class Login extends React.Component { render(){ return < _Login service={service}/> } } @observer class _Login extends React.Component{ handlerClick(event){ event.preventDefault(); //其默认是写一条数据提交一次,此命令用于阻止其默认提交 console.log('this----------',this) //此处的this指的是Login 实例,可将此值传入进去用于修改ret 的值来触发页面刷新 let fm=event.target.form this.props.service.login(fm[0].value,fm[1].value,this); } render(){ if ( this.props.service.loggin) return <Redirect to='/about' /> return ( <div className="login-page"> <div className="form"> <form className="register-form"> <input type="text" placeholder="邮箱" defaultValue="12345@123"/> <input type="password" placeholder="密码" defaultValue="demo"/> <button onClick={this.handlerClick.bind(this)}>登陆</button> {/*触发按钮*/} <p className="message">还未注册 <Link to="/reg">请注册</Link></p> </form> </div> </div> ) } }
总体结果以下
let a=1,b=2,c=3 var obj={a,b,c} console.log(obj)
结果以下
src/service/user.js中配置以下
import axios from 'axios' import {observable} from 'mobx' import store from 'store' store.addPlugin(require('store/plugins/expire')) //加载过时插件,此处返回一个对象 //用户逻辑的处理 export default class UserService{ @observable loggin=0; // 被观察对象,已经被观察了,一旦值发生变化,则观察者就知道了 @observable regin=0; //定义登陆的被观察对象 login(email,password) { axios.post('/api/user/login', { 'email': email, 'password': password }) .then( (response) => { //成功执行的操做 this的问题经过箭头函数解决 console.log(response,'==================='); console.log(response.data) console.log(response.status); // obj.setState({ret:1000}) //state触发致使改变 store.set('token',response.data.token,(new Date()).getTime()+(8*3600*1000));//getTime拿到的是时间,但其是毫秒 this.loggin = Math.random() * 100; // 修改值 console.log(this.loggin) }) .catch( (error) => { //失败执行的操做 console.log(error); }); //for (var d=new Date();(new Date())-d < 10*1000;); // 此处是同步处理 console.log(email,password,'UserService')// 如何传输,传输什么,返回什么,如何返回的问题 } reg(name,email,password){ axios.post('/api/user/reg',{ name,email,password} ).then((response)=> { console.log(response.data); this.regin=parseInt(Math.random()*100); //改变触发 store.set('token',response.data.token,(new Date()).getTime()+(8*3600*1000));//getTime拿到的是时间,但其是毫秒 }).catch((error)=> { console.log(error.data); }) } }
src/component/reg.js中配置以下
import React from 'react'; import '../css/login.css' import {Link,Redirect} from 'react-router-dom'; import UserService from '../service/user' import {observer} from 'mobx-react' const service= new UserService(); export default class Reg extends React.Component{ render(){ return <_Reg service={service} />; {/*经过此处将service传递下去,后期能够经过props.service.xxx方法来完成数据的注入操做*/} } } @observer class _Reg extends React.Component { handleClick(event) { event.preventDefault(); //处理页面刷新问题,阻止缺省行为 let fm=event.target.form; console.log(fm[0].value,fm[1].value,fm[2].value,fm[3].value) //获取注册信息 this.props.service.reg(fm[0].value,fm[1].value,fm[2].value) console.log(this.props.service.regin) } render() { if (this.props.service.regin) return <Redirect to='/about' /> return ( <div className="login-page"> <div className="form"> <form className="register-form"> <input type="text" placeholder="用户名"/> <input type="text" placeholder="邮箱"/> <input type="password" placeholder="密码"/> <input type="password" placeholder="确认密码"/> <button onClick={this.handleClick.bind(this)}>注册</button> {/*触发按钮*/} <p className="message">已经注册 <Link to="/reg">请登陆</Link></p> </form> </div> </div> ) } }
网页开发中,无论操做成功与否,有不少提示信息,目前信息都是从控制台输出的,用户看不到,使用Antd的message组件显示友好的信息提示。
import React from 'react'; import ReactDom from 'react-dom'; import { BrowserRouter as Router, Route, Link } from "react-router-dom"; import Login from './component/login'; import Reg from './component/reg'; import { message } from 'antd'; import 'antd/lib/message/style' const info = () =>{ message.info('触发构建') } class Root extends React.Component{ render(){ return (<div> <button type="prmary" onClick={info}>点击触发</button> </div>) } } ReactDom.render(<Root />,document.getElementById('root'));
结果以下
import React from 'react'; import ReactDom from 'react-dom'; import { BrowserRouter as Router, Route, Link } from "react-router-dom"; import Login from './component/login'; import Reg from './component/reg'; import { message } from 'antd'; import 'antd/lib/message/style' const info = () =>{ message.success('this is first',5) //此处的5为显示延迟为5 } class Root extends React.Component{ render(){ return (<div> <button type="prmary" onClick={info}>点击触发</button> </div>) } } ReactDom.render(<Root />,document.getElementById('root'));
import React from 'react'; import ReactDom from 'react-dom'; import { BrowserRouter as Router, Route, Link } from "react-router-dom"; import Login from './component/login'; import Reg from './component/reg'; import { message } from 'antd'; import 'antd/lib/message/style' const info = () =>{ message.success('this is first',5) message.info('this is info') } class Root extends React.Component{ render(){ return (<div> <button type="prmary" onClick={info}>点击触发</button> </div>) } } ReactDom.render(<Root />,document.getElementById('root'));
结果以下
index.js代码还原
代码修改以下
import axios from 'axios' import {observable} from 'mobx' import store from 'store' store.addPlugin(require('store/plugins/expire')) //加载过时插件,此处返回一个对象 //用户逻辑的处理 export default class UserService{ @observable loggin=0; // 被观察对象,已经被观察了,一旦值发生变化,则观察者就知道了 @observable regin=0; //定义登陆的被观察对象 @observable loginerrMsg=''; //定义发生登陆错误的输出结果 @observable regerrMsg=''; //定义注册发生错误的输出结果 login(email,password) { axios.post('/api/user/login', { 'email': email, 'password': password }) .then( (response) => { //成功执行的操做 this的问题经过箭头函数解决 console.log(response,'==================='); console.log(response.data) console.log(response.status); // obj.setState({ret:1000}) //state触发致使改变 store.set('token',response.data.token,(new Date()).getTime()+(8*3600*1000));//getTime拿到的是时间,但其是毫秒 this.loggin = Math.random() * 100; // 修改值 console.log(this.loggin) }) .catch( (error) => { //失败执行的操做 console.log(error); this.loginerrMsg=true; //当发生错误时触发 }); //for (var d=new Date();(new Date())-d < 10*1000;); // 此处是同步处理 console.log(email,password,'UserService')// 如何传输,传输什么,返回什么,如何返回的问题 } reg(name,email,password){ axios.post('/api/user/reg',{ name,email,password} ).then((response)=> { console.log(response.data); this.regin=parseInt(Math.random()*100); //改变触发 store.set('token',response.data.token,(new Date()).getTime()+(8*3600*1000));//getTime拿到的是时间,但其是毫秒 }).catch((error)=> { this.regerrMsg=true; //当发生错误时进行触发 console.log(error.data); }) } }
src/component/login.js代码以下
import React from 'react'; import '../css/login.css' import {Link,Redirect} from 'react-router-dom'; import UserService from '../service/user' import {observer} from 'mobx-react' import { message } from 'antd'; let service = new UserService() export default class Login extends React.Component { render(){ return < _Login service={service}/> } } @observer class _Login extends React.Component{ handlerClick(event){ event.preventDefault(); //其默认是写一条数据提交一次,此命令用于阻止其默认提交 console.log('this----------',this) //此处的this指的是Login 实例,可将此值传入进去用于修改ret 的值来触发页面刷新 let fm=event.target.form this.props.service.login(fm[0].value,fm[1].value,this); } render(){ if ( this.props.service.loggin) return <Redirect to='/about' /> if (this.props.service.loginerrMsg) { message.error('用户名或密码错误',3,()=>{ this.props.service.loginerrMsg=''; }) } return ( <div className="login-page"> <div className="form"> <form className="register-form"> <input type="text" placeholder="邮箱" defaultValue="12345@123"/> <input type="password" placeholder="密码" defaultValue="demo"/> <button onClick={this.handlerClick.bind(this)}>登陆</button> {/*触发按钮*/} <p className="message">还未注册 <Link to="/reg">请注册</Link></p> </form> </div> </div> ) } }
src/component/reg.js代码以下
import React from 'react'; import '../css/login.css' import {Link,Redirect} from 'react-router-dom'; import UserService from '../service/user' import {observer} from 'mobx-react' import { message } from 'antd'; const service= new UserService(); export default class Reg extends React.Component{ render(){ return <_Reg service={service} />; {/*经过此处将service传递下去,后期能够经过props.service.xxx方法来完成数据的注入操做*/} } } @observer class _Reg extends React.Component { handleClick(event) { event.preventDefault(); //处理页面刷新问题,阻止缺省行为 let fm=event.target.form; console.log(fm[0].value,fm[1].value,fm[2].value,fm[3].value) //获取注册信息 this.props.service.reg(fm[0].value,fm[1].value,fm[2].value) console.log(this.props.service.regin) } render() { if (this.props.service.regin) return <Redirect to='/about' /> if (this.props.service.regerrMsg){ message.error('注册失败,请检查相关参数是否正确',3,()=>this.props.service.regerrMsg='') } return ( <div className="login-page"> <div className="form"> <form className="register-form"> <input type="text" placeholder="用户名"/> <input type="text" placeholder="邮箱"/> <input type="password" placeholder="密码"/> <input type="password" placeholder="确认密码"/> <button onClick={this.handleClick.bind(this)}>注册</button> {/*触发按钮*/} <p className="message">已经注册 <Link to="/reg">请登陆</Link></p> </form> </div> </div> ) } }
结果以下
/post/put POST 提交博文的title,content,成功返回JSON的post_id
/post/id GET 返回博文详情。返回JSON的post_id,title,author,author_id,postdate(时间戳),conent 内容
/post/GET 返回博文列表
https://ant.design/components/layout-cn/
index.js中代码以下
import React from 'react'; import ReactDom from 'react-dom'; import { BrowserRouter as Router, Route, Link } from "react-router-dom"; import Login from './component/login'; import Reg from './component/reg'; import Pub from './component/pub' import 'antd/lib/menu/style' import 'antd/lib/icon/style' import 'antd/lib/layout/style' import { Menu, Icon, Layout,Item} from 'antd' const { Header, Content, Footer } = Layout; const Home =() => { return ( <div> <h2>Home</h2> </div> ); } const About=() => { return ( <div> <h2>About</h2> </div> ); } class Root extends React.Component { render() { return ( <Router> <div> <ul> <li><Link to="/">主页</Link></li> <li><Link to="/about">关于</Link></li> <li><Link to="/reg">注册</Link></li> <li><Link to="/login">登陆</Link></li> <li><Link to="/pub">博客上传</Link></li> </ul> <Route exact path="/" component={Home} /> <Route path="/about" component={About} /> <Route path="/login" component={Login} /> <Route path="/reg" component={Reg} /> <Route path="/pub" component={Pub} /> </div> </Router> ) } } ReactDom.render(<Root />,document.getElementById('root'));
service/post.js
import axios from 'axios' import {observable} from 'mobx' import store from 'store' export default class PostService { constructor(){ this.instance=axios.create({ baseURL:'/api/post', }); } @observable msg=""; pub(title,content) { console.log(title,content) this.instance.post('/pub',{ title,content },{ headers:{'jwt':store.get('token')} }).then((response) => { console.log(response.data), console.log(Response.status); this.msg="博文提交成功"; // 触发事件 }).catch((error)=> { console.log(error.data); this.msg="博文提交失败"; }) } }
From 表单组件,layout是垂直,onsubmit提交,注意这个提交的this是表单本身
FromItem 表单向,label设置控件的标题,labelCol设置label的宽度,wrapperCol是label后占的宽度,这些都是栅格系统的宽度
INput 输入框,placeholder 提示字符
TextArea文本框,rows 行数
Button按钮。htmlType使用HTML中的type值。submit是提交按钮会触发提交行为,可是handleSubmit中要阻止此行为。
/src/component/pub.js
import React from 'react'; import '../css/login.css' import {Link,Redirect} from 'react-router-dom'; import UserService from '../service/post' import {observer} from 'mobx-react' import { Input,message,Button,Form } from 'antd'; import PostService from '../service/post' const {TextArea} = Input; import 'antd/lib/message/style' import 'antd/lib/form/style' import 'antd/lib/input/style' import 'antd/lib/button/style' export default class Pub extends React.Component{ render(){ return <_Pub service={new PostService()} /> } } @observer class _Pub extends React.Component{ handleSubmit(event){ event.preventDefault(); console.log('pub......') let fm=event.target; console.log(fm[0].value,fm[1].value) this.props.service.pub(fm[0].value,fm[1].value) } render(){ if (this.props.service.failsg) { message.error(this.props.service.msg,5,()=> this.props.service.msg='') } if (this.props.service.semsg) { message.success(this.props.service.semsg,5,()=> this.props.service.semsg='') } return ( <Form onSubmit={this.handleSubmit.bind(this)} > <Form.Item label="标题" wrapperCol={{span:20}} labelCol={{span:2}}> <Input /> </Form.Item> <Form.Item label="内容" wrapperCol={{span:20}} labelCol={{span:2}}> <TextArea rows={28}/> </Form.Item> <Form.Item wrapperCol={{span:4,offset:10}}> <Button type="primary" htmlType="submit" >发布</Button> </Form.Item> </Form> ); } }
此处显示须要用到ist,相关连接以下
https://ant.design/components/list-cn/ https://ant.design/components/form-cn/ https://ant.design/components/input-cn/
配置渲染页面
在component 中建立Getall.js文件,内容以下
import React from 'react'; import { observer } from 'mobx-react'; import PostService from '../service/post'; import 'antd/lib/message/style'; import 'antd/lib/form/style'; import 'antd/lib/input/style'; import 'antd/lib/button/style'; @observer export default class Getall extends React.Component{ constructor(props){ super(props); console.log(props); } render(){ return <h1>Getall</h1> } }
将其加入到index.js中显示结果以下
在输入框中写入http://localhost/list?page=1&size=10 结果以下
由上图可知,其props中包含页面输入框的内容,提取以下
import React from 'react'; import { observer } from 'mobx-react'; import PostService from '../service/post'; import 'antd/lib/message/style'; import 'antd/lib/form/style'; import 'antd/lib/input/style'; import 'antd/lib/button/style'; @observer export default class Getall extends React.Component{ constructor(props){ super(props); let {location:{search}}=props; console.log(search) //获取数据 } render(){ return <h1>Getall</h1> } }
结果以下
/src/component/getall.js 中代码以下
import React from 'react'; import { observer } from 'mobx-react'; import PostService from '../service/post'; import { List, Avatar,Pagination } from 'antd'; import 'antd/lib/list/style' import 'antd/lib/avatar/style' import 'antd/lib/pagination/style' @observer export default class Getall extends React.Component{ constructor(props){ super(props); let {location:{search}}=props; this.service=new PostService(); this.service.getall(search); } handleChange(page,pageSize){ console.log(page,pageSize) let search ='?'+'page='+page+'&'+'size='+pageSize; console.log(search) this.service.getall(search) } render(){ const data=this.service.posts; //获取数据列表 const pagination=this.service.pagination; //分页功能实现 return ( <div> <List itemLayout="horizontal" dataSource={data} bordered="true" split="true" hideOnSinglePage="true" renderItem={item => ( <List.Item> <List.Item.Meta avatar={<Avatar src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1571932022162&di=f108eeab8bc4d45e6d9b85c36581f9ae&imgtype=0&src=http%3A%2F%2Fs7.sinaimg.cn%2Fmw690%2F0065sEcMzy74EYHBPMOa6%26690" />} title={item.name} description={item.title} /> </List.Item> )} /> <Pagination defaultCurrent={1} total={pagination.count} pageSize={pagination.size} onChange={this.handleChange.bind(this)}/> </div> ) } }
/src/service/post.js
import axios from 'axios' import { observable } from 'mobx' import store from 'store' export default class PostService { constructor() { this.instance = axios.create({ baseURL: '/api/post', }); } @observable semsg = ""; @observable failsg = ""; @observable posts = []; //定义输出结果至此容器中 @observable pagination = ''; //定义分页功能相关参数监控 pub(title, content) { console.log(title, content) this.instance.post('/pub', { title, content }, { headers: { 'jwt': store.get('token') } }).then((response) => { console.log(response.data), console.log(Response.status); this.semsg = "博文提交成功"; // 触发事件 }).catch((error) => { console.log(error.data); this.failsg = "博文提交失败"; }) } getall(search) { axios.get('/api/post/' + search).then( response => { console.log(response.data) this.posts = response.data.posts; //成功的输出结果 this.pagination = response.data.pagination; //携带的相关参数 } ).catch(error=> { console.log(error.data) }) } }
结果以下
import React from 'react'; import { observer } from 'mobx-react'; import PostService from '../service/post'; import { Card,Row } from 'antd'; export default class Get extends React.Component{ constructor(props){ super(props); this.service=new PostService(); console.log(props); } render(){ return (<div> Get </div>) } }
将其加入index.js中结果查看以下
有上述得知,其id获取还是经过pathname来完成,具体代码以下
/src/component/get.js
import React from 'react'; import { observer } from 'mobx-react'; import PostService from '../service/post'; import { Card,Row, message } from 'antd'; import 'antd/lib/card/style' @observer export default class Get extends React.Component{ constructor(props){ super(props); this.service=new PostService(); let {location:{pathname}}=this.props; let [,,id]=pathname.split('/') // 获取ID this.service.get(id) //异步传值到后端 } render(){ let s=this.service; if (s.getMsg) { message.error("获取文章失败",3,()=> s.getMsg=false) } let post=s.post; return <Card title={post.title} bordered={true} style={{width:600}}> <p>{post.author} {new Date(post.postdate*1000).toLocaleDateString()} </p> <p>{post.content}</p> </Card> } }
/src/service/post.js
import axios from 'axios' import { observable } from 'mobx' import store from 'store' export default class PostService { constructor() { this.instance = axios.create({ baseURL: '/api/post', }); } @observable semsg = ""; @observable failsg = ""; @observable posts = []; //定义输出结果至此容器中 @observable pagination = ''; //定义分页功能相关参数监控 @observable post=''; //定义get 获取到的详细的页面数据 @observable getMsg=false;// 定义get 获取是否获取数据成功返回处理 pub(title, content) { console.log(title, content) this.instance.post('/pub', { title, content }, { headers: { 'jwt': store.get('token') } }).then((response) => { console.log(response.data), console.log(Response.status); this.semsg = "博文提交成功"; // 触发事件 }).catch((error) => { console.log(error.data); this.failsg = "博文提交失败"; }) } getall(search) { axios.get('/api/post/' + search).then( response => { console.log(response.data) this.posts = response.data.posts; //成功的输出结果 this.pagination = response.data.pagination; //携带的相关参数 } ).catch(error=> { console.log(error.data) }) } get(id){ axios.get('/api/post/'+id).then(response =>{ console.log(response.data) this.post=response.data.post; }).catch(error => { console.log(error.data) this.getMsg=true; }) } }
结果以下
经过getall中获取的post_id 进行跳转到localhost/get/x
import React from 'react'; import { observer } from 'mobx-react'; import PostService from '../service/post'; import { List, Avatar,Pagination,Link } from 'antd'; import 'antd/lib/list/style' import 'antd/lib/avatar/style' import 'antd/lib/pagination/style' @observer export default class Getall extends React.Component{ constructor(props){ super(props); let {location:{search}}=props; this.service=new PostService(); this.service.getall(search); } handleChange(page,pageSize){ console.log(page,pageSize) let search ='?'+'page='+page+'&'+'size='+pageSize; console.log(search) this.service.getall(search) } render(){ const data=this.service.posts; //获取数据列表 const pagination=this.service.pagination; //分页功能实现 return ( <div> <List itemLayout="horizontal" dataSource={data} bordered="true" split="true" hideOnSinglePage="true" renderItem={item => ( <List.Item> <List.Item.Meta avatar={<Avatar src="https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1571932022162&di=f108eeab8bc4d45e6d9b85c36581f9ae&imgtype=0&src=http%3A%2F%2Fs7.sinaimg.cn%2Fmw690%2F0065sEcMzy74EYHBPMOa6%26690" />} title={<a href={'/get/'+item.post_id}>{item.title}</a>} description={item.title} /> </List.Item> )} /> <Pagination defaultCurrent={1} total={pagination.count} pageSize={pagination.size} onChange={this.handleChange.bind(this)}/> </div> ) } }
结果以下
此处传入是一个类,返回也是一个类
function inject(Comp) { return class extends React.Component { render(){ return <Comp service={service} /> } } }
提取参数以下
function inject(Comp,service) { return class extends React.Component{ render() { return <Comp service={service} /> } } }
使用可变参数进行处理
function inject(...obj,Comp){ return class extends React.Component{ render(){ return <Comp {...obj} /> } } }
柯里化
function inject(obj){ function wrapper(Comp) { return class extends React.Component{ render(){ return <Comp {...obj} /> } } } return wrapper; }
变形
function inject(obj){ return function wrapper(Comp) { return class extends React.Component{ render(){ return <Comp {...obj} /> } } } }
箭头函数变形
const inject = obj => Comp => { return class extends React.Component{ render(){ return <Comp {...obj} /> } } }
函数式组件简化
const insject = obj=> Comp=> { return props => <Comp {...obj} /> }
继续简化以下
const insject = obj=> Comp => props => <Comp {...obj} {...props} />
建立utils.js文件,和src 在同一级目录,以下
import React from 'react'; const insject = obj=> Comp => props => <Comp {...obj} {...props}/> export {insject}
/src/component/login.js
import React from 'react'; import '../css/login.css' import {Link,Redirect} from 'react-router-dom'; import UserService from '../service/user' import {observer} from 'mobx-react' import { message } from 'antd'; let service = new UserService() import { insject } from "../utils"; @insject({service}) @observer export default class Login extends React.Component{ handlerClick(event){ event.preventDefault(); //其默认是写一条数据提交一次,此命令用于阻止其默认提交 console.log('this----------',this) //此处的this指的是Login 实例,可将此值传入进去用于修改ret 的值来触发页面刷新 let fm=event.target.form this.props.service.login(fm[0].value,fm[1].value,this); } render(){ if ( this.props.service.loggin) return <Redirect to='/getall' /> if (this.props.service.loginerrMsg) { message.error('用户名或密码错误',3,()=>{ this.props.service.loginerrMsg=''; }) } return ( <div className="login-page"> <div className="form"> <form className="register-form"> <input type="text" placeholder="邮箱" defaultValue="12345@123"/> <input type="password" placeholder="密码" defaultValue="demo"/> <button onClick={this.handlerClick.bind(this)}>登陆</button> {/*触发按钮*/} <p className="message">还未注册 <Link to="/reg">请注册</Link></p> </form> </div> </div> ) } }
/src/component/reg.js
import React from 'react'; import '../css/login.css' import {Link,Redirect} from 'react-router-dom'; import UserService from '../service/user' import {observer} from 'mobx-react' import { message } from 'antd'; import { insject } from "../utils"; const service= new UserService(); @insject({service}) @observer export default class Reg extends React.Component { handleClick(event) { event.preventDefault(); //处理页面刷新问题,阻止缺省行为 let fm=event.target.form; console.log(fm[0].value,fm[1].value,fm[2].value,fm[3].value) //获取注册信息 this.props.service.reg(fm[0].value,fm[1].value,fm[2].value) console.log(this.props.service.regin) } render() { if (this.props.service.regin) return <Redirect to='/about' /> if (this.props.service.regerrMsg){ message.error('注册失败,请检查相关参数是否正确',3,()=>this.props.service.regerrMsg='') } return ( <div className="login-page"> <div className="form"> <form className="register-form"> <input type="text" placeholder="用户名"/> <input type="text" placeholder="邮箱"/> <input type="password" placeholder="密码"/> <input type="password" placeholder="确认密码"/> <button onClick={this.handleClick.bind(this)}>注册</button> {/*触发按钮*/} <p className="message">已经注册 <Link to="/reg">请登陆</Link></p> </form> </div> </div> ) } }
https://ant.design/components/layout-cn/
import React from 'react'; import ReactDom from 'react-dom'; import { BrowserRouter as Router, Route, Link } from "react-router-dom"; import Login from './component/login'; import Reg from './component/reg'; import Pub from './component/pub' import Get from './component/get' import Getall from './component/Getall'; import 'antd/lib/menu/style' import 'antd/lib/icon/style' import 'antd/lib/layout/style' import { Layout, Menu,Icon } from 'antd'; const { Header, Content, Footer } = Layout; import 'antd/lib/layout/style' import 'antd/lib/menu/style' const Home =() => { return ( <div> <h2>Home</h2> </div> ); } class Root extends React.Component { render() { return ( <Router> <Layout> <Header style={{ position: 'fixed', zIndex: 1, width: '100%' }} > <div className="logo" /> <Menu theme="dark" mode="horizontal" defaultSelectedKeys={['1']} style={{ lineHeight: '65px' }}> <Menu.Item key="home"> <Link to="/"><Icon type="home" /> 主页</Link> </Menu.Item> <Menu.Item key="login"> <Link to="/login"><Icon type="login" />登录</Link> </Menu.Item> <Menu.Item key="reg"> <Link to="/reg"><Icon type="home" />注册</Link> </Menu.Item> <Menu.Item key="pub"> <Link to="/pub"><Icon type="home" />上传</Link> </Menu.Item> <Menu.Item key="getall"> <Link to="/getall"><Icon type="home" />列表查看</Link> </Menu.Item> <Menu.Item key="get"> <Link to="/get"><Icon type="bars" />详情页</Link> </Menu.Item> </Menu> </Header> <h1></h1> <h1></h1> <h1></h1> <h1></h1> <h1></h1> <Content style={{ padding: '5px 20px' }}> <div style={{ background: '#fff', padding: 30, minHeight: 50}}> <Route exact path="/" component={Home} /> <Route path="/login" component={Login} /> <Route path="/reg" component={Reg} /> <Route path="/pub" component={Pub} /> <Route path="/getall" component={Getall} /> <Route path="/get" component={Get} /> </div> </Content> <Footer style={{ textAlign: 'center' }}>Ant Design ©2018 Created by Ant UED</Footer> </Layout> </Router> ) } } ReactDom.render(<Root />,document.getElementById('root'));
结果以下
至此,前端页面开发完成