多人博客开发项目-前端

一 开发环境设置

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

结果如下

多人博客开发项目-前端

至此,前端页面开发完成

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