多人博客開發項目-前端

一 開發環境設置

1 安裝包環境

項目包如下
鏈接:https://pan.baidu.com/s/1C-ZY9rWU-8ZugE4EwVveWw
提取碼:744p


相關react介紹鏈接如下
https://blog.51cto.com/11233559/2443713

解壓並修改目錄爲blog 沒有特殊說明,js 文件均放置在src目錄中

2 修改相關信息

1 修改項目信息

多人博客開發項目-前端

2 修改反代和本地監聽端口

本環境後端服務ip地址爲192.168.1.200,後端python監聽端口爲80.

多人博客開發項目-前端

3 安裝軟件

npm  i

多人博客開發項目-前端

啓動並查看

npm  start  

多人博客開發項目-前端

多人博客開發項目-前端

二 登錄模塊功能開發

1 前端路由配置

本次使用react-router 進行路由配置工作
基礎例子

https://reacttraining.com/react-router/web/example/basic

官方文檔

https://reacttraining.com/react-router/web/guides/quick-start

根據官方示例,修改src/index.js如下

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'));

顯示結果如下

多人博客開發項目-前端

多人博客開發項目-前端

Route 負責靜態路由
path 是匹配的路徑,沒有path總是匹配。
component 是目標組件。
exact: 布爾值,true 時要求路徑完全匹配。
strict: 布爾值,true 時要求嚴格匹配,但是url字符串可以是自己的字串。

地址變化,Router組件會匹配路徑,然後使用匹配的組件進行渲染

2 登錄前端view層實現

1 全局CSS 配置

添加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;
}

如下

多人博客開發項目-前端

2登錄模塊view層實現

在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

3 獲取觸發數據

在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可獲取到表單提交的數據

3 註冊界面view 實現

1 基本頁面實現

在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 中直接獲取

4 導航欄組件

在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'));

結果如下

多人博客開發項目-前端

5 同步和異步

1 同步

模擬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)
    }
}

結果導致瀏覽器端在進行數據請求時直接停頓,導致其他相關頁面也不能刷新或者點開

2 異步

1 setTimeout

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)}) 此處用於生成隨機整數

2 Promise

官網代碼如下

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並未阻塞程序本身的運行,此處便是異步調用方式。其不會影響當前請求的下一個數據處理

多人博客開發項目-前端

3 axios

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);
  });

6 登錄接口實現

具體代碼如下

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 是爲了方便登錄而處理的。

獲取數據如下

多人博客開發項目-前端

7 localStorage及過期實現

使用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));

8 Mobx 狀態管理

1 需求

一個組件的onClick 觸發事件響應函數,此函數會調用後臺服務,但是後臺服務比較耗時,等處理完成,需要引起組件的渲染操作。
要組件渲染,則需要改變組件的props或state

1 同步調用

將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秒頁面進行刷新,但其在此期間不能點擊其他頁面

2 異步調用

思路一,使用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'));

結果如下

多人博客開發項目-前端

上述方式在事件被調用的過程中,其沒有影響到頁面的點擊,不會阻塞頁面的正常處理。

3 Mobx 實現

observable裝飾器: 設置被觀察者

observer 裝飾器:設置觀察者

1 Mobx + promise 實現代碼

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'));

其基本結論和上面的相同,其點擊不會導致頁面問題,實現了異步請求的目的

2 mobx+axiso 代碼實現

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>
        )
    }
} 

整體結果如下

多人博客開發項目-前端

9 註冊接口完善

1 參數解構

let a=1,b=2,c=3
var obj={a,b,c}
console.log(obj)

結果如下

多人博客開發項目-前端

2 註冊接口完善

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>       
           )
        }  
      }

多人博客開發項目-前端

10 增加信息提示

網頁開發中,不管操作成功與否,有很多提示信息,目前信息都是從控制檯輸出的,用戶看不到,使用Antd的message組件顯示友好的信息提示。

1 臨時修改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 { 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'));

多人博客開發項目-前端

2 同時觸發多條數據

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'));

結果如下

多人博客開發項目-前端

3 業務添加提示信息

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>       
           )
        }  
      }

結果如下

多人博客開發項目-前端

三 博文模塊功能開發

1 接口規則相關

/post/put POST 提交博文的title,content,成功返回JSON的post_id

/post/id GET 返回博文詳情。返回JSON的post_id,title,author,author_id,postdate(時間戳),conent 內容

/post/GET 返回博文列表

2 上傳博文相關配置

1 相關文檔

https://ant.design/components/layout-cn/

2 前端路由配置

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'));

3 後端服務配置

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="博文提交失敗";
        })
    }
}

4 渲染頁面配置

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>
                    );
                } 
            }

5 結果如下

多人博客開發項目-前端

3 查看博文列表相關配置及getall

1 相關文檔

此處顯示需要用到ist,相關鏈接如下

https://ant.design/components/list-cn/
https://ant.design/components/form-cn/
https://ant.design/components/input-cn/

2 測試頁面數據獲取

配置渲染頁面
在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>
    }

}

結果如下

多人博客開發項目-前端

3 顯示層代碼實現

/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>

        )
    }
}

4 邏輯層代碼如下

/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)
        })
    }
} 

結果如下

多人博客開發項目-前端

4 詳情頁get配置

1 獲取id數據

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來完成,具體代碼如下

2 view層代碼如下

/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>  
        }
    }

3 業務層代碼如下

/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;

        })
    }
} 

結果如下

多人博客開發項目-前端

5 通過getall頁面跳轉至詳情頁面

通過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>

        )
    }
}

結果如下

多人博客開發項目-前端

4 高階組件裝飾器

1 基本代碼概述

此處傳入是一個類,返回也是一個類

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} />

2 創建外置函數,用於處理service的傳入問題

創建utils.js文件,和src 在同一級目錄,如下

多人博客開發項目-前端

import React  from  'react';
const insject = obj=> Comp =>  props => <Comp {...obj} {...props}/>
export  {insject}

3 修改登陸和註冊view代碼

/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>       
           )
        }  
      }

5 index.js頁面添加布局

1 相關文檔如下

https://ant.design/components/layout-cn/

2 具體代碼如下

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'));

結果如下

多人博客開發項目-前端

至此,前端頁面開發完成

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章