項目包以下
連接: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'));
結果以下
至此,前端頁面開發完成