博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
前端开发及登录功能实现(项目源码:https://github.com/sqsltr520/python)
阅读量:4131 次
发布时间:2019-05-25

本文共 13029 字,大约阅读时间需要 43 分钟。

1. 前端开发环境设置

使用react-mobx-starter-master脚手架,解压更名为frontend。在src中新增componentservicecss目录。

修改项目信息:

{"name": "blog","description": "blog project","author": "sun"}

webpack.confifig.dev.js

devServer: {        compress: true,        port: 3001,        publicPath: '/assets/',        hot: true,        inline: true,        historyApiFallback: true,        stats: {            chunks: false        },        proxy: {            '/api': {                target: 'http://127.0.0.1:8000',                changeOrigin: true,                pathRewrite: {"^/api": ""}  # 路径重写            }        }    }

安装依赖:$ npm install

npm会安装package.json中依赖的包。也可以使用新的包管理工具yarn安装模块

yarn安装$ npm install -g yarn或者,去 https://yarn.bootcss.com/docs/install/相当于 npm install$ yarn相当于npm install react-router$ yarn add react-router$ yarn add react-router-dom

1.1 前端路由

前端路由使用react-router组件完成

官网文档 https://reacttraining.com/react-router/web/guides/quick-start

基本例子 https://reacttraining.com/react-router/web/example/basic

使用react-router组件,更改src/index.js

import React from 'react';import ReactDom from 'react-dom';import {Route, Link, BrowserRouter as Router, Switch} from 'react-router-dom';const Home = () => (    

Home

);const About = () => (

About

);const App = () => (
);ReactDom.render(
, document.getElementById('root'));

Route指令:

  • 它负责静态路由,只能和Route指令的path匹配,组件就可以显示。URL变化,将重新匹配路径
  • component属性设置目标组件
  • path是匹配路径,如果匹配则显示组件:exact:布尔值 ;strict:布尔值
  • 没有path属性,组件将总是显示,例如 <Route component={Always} />
  • path属性还支持路径数组,意思是多个路径都可以匹配

路径匹配:

exact 只能匹配本路径,不包含子路径;strict 路径尾部有/,则必须匹配这个/,也可以匹配子路径 ;exact strict 一起用,表示严格的等于当前指定路径

Switch指令:也可以将Route组织到一个Switch中,一旦匹配Switch中的一个Route,就不再匹配其它。但是Route是匹配所 有,如果匹配就会显示组件,无pathRoute始终匹配。

 

登录组件:component目录下构建react组件。登录页模板 https://codepen.io/colorlib/pen/rxddKy?q=login&limit=all&type=type-pens;

特别注意 :

  • 搬到React组件中的时候,要将class属性改为className
  • 所有标签,需要闭合。

login.js

component目录下建立login.js的登录组件。 使用上面的模板的HTML中的登录部分,挪到render函数中。 修改classclassName

  • <a> 标签替换成 <Link to="?"> 组件
  • 注意标签闭合问题
import React from 'react';import {Link} from 'react-router-dom';export default class Login extends React.Component {    render() {        return (

还未注册?

请注册

); }}

index.js:在路由中增加登录组件:

import Login from './component/login';const App = () => (
);

注册组件:与登录组件编写方式差不多,创建component/reg.js,使用login.css

 

import React from 'react';import { Link } from 'react-router-dom';import '../css/login.css'export default class Reg extends React.Component {    render() {        return (            

如果已经注册

请登录

); }}

分层:

1.2 登录功能的实现

  • view层,登录组件和用户交互。当button点击触发onClick,调用事件响应函数handleClickhandleClick中调用 服务service层的login函数。
  • service层,负责业务逻辑处理。调用Model层数据操作函数

src/service/user.js

export default class UserService {    login (email, password) {    // TODO    }}

src/component/login.js:

// src/component/login.jsimport React from 'react';import {Link} from 'react-router-dom';import '../css/login.css'export default class Login extends React.Component {    handleClick(event) {        console.log(event.target)        }    render() {        return (

还未注册?

请注册

); }}

问题:

  • 页面提交 ,这一次发现有一些问题,按钮点击会提交,导致页面刷新了。 要阻止页面刷新,其实就是阻止提交。使用event.preventDefault()
  • 如何拿到邮箱和密码? event.target.form返回按钮所在表单,可以看做一个数组。 fm[0].valuefm[1].value就是文本框的值。
  • 如何在Login组件中使用UserService实例呢? 使用全局变量,虽然可以,但是不好。 可以在Login的构造器中通过属性注入。 也可以在外部使用props注入。使用这种方式。
import React from 'react';import {Link} from 'react-router-dom';import '../css/login.css'import UserService from '../service/user';const service = new UserService();export default class Login extends React.Component {    render() {        return <_Login service={service} />;    }}class _Login extends React.Component {    handleClick(event) {        event.preventDefault();        let fm = event.target.form;        this.props.service.login(        fm[0].value, fm[1].value        );    }    render() {        return (

还未注册?

请注册

); }}

1.3 UserServicelogin方法实现

代理设置:修改webpack.confifig.dev.js文件中proxy部分,要保证proxytarget是后台服务的地址和端口,且要开启后台服 务。注意,修改这个配置,需要重启dev server

axios异步库:axios是一个基于PromiseHTTP异步库,可以用在浏览器或nodejs中。 使用axios发起异步调用,完成POSTGET方法的数据提交。可参照官网的例子。中文说明 https://www.kancloud.cn/yunye/axios/234845

安装:$ yarn add axios

service/user.js修改如下:

import axios from 'axios';export default class UserService {    login (email, password) {        console.log(email, password);        axios.post('/api/users/login', {        email:email,        password:password    })/* dev server会代理 */    .then(        function (response) {            console.log(response);            console.log(response.data);            console.log(response.status);            console.log(response.statusText);            console.log(response.headers);            console.log(response.config);        }    ).catch(        function (error) {        console.log(error);        }        )    }}

问题:

404:填入邮箱、密码,点击登录按钮,返回404,查看Python服务端,访问地址是 /api/users/login ,也就是多

/api。如何解决?

1、修改blog server的代码的路由匹配规则,不建议这么做,影响有点大

2rewrite,类似httpdnginx等的rewrite功能。本次测试使用的是dev server,去官方看看。https://webpack.js.org/confifiguration/dev-server/#devserver-proxy

可以查到pathRewrite可以完成路由重写。

devServer: {        compress: true,        port: 3001,        publicPath: '/assets/',        hot: true,        inline: true,        historyApiFallback: true,        stats: {            chunks: false        },        proxy: {            '/api': {                target: 'http://127.0.0.1:8000',                changeOrigin: true,                pathRewrite: {"^/api": ""}            }        }    }

重启dev server。使用正确的邮箱、密码登录,返回了json数据,在response.data中可以看到tokenuser

store.js:store.js 是一个兼容所有浏览器的 LocalStorage 包装器,不需要借助 Cookie 或者 Flashstore.js 会根据浏览器自动选择使用 localStorageglobalStorage 或者 userData 来实现本地存储功能。

安装:$ yarn add store

let store = require('store')store.set('user', 'sun')console.log(store.get('user'))store.remove('user')console.log(store.get('user'))console.log(store.get('user', 'a'))store.set('user', {name:'sun', age: 29})console.log(store.get('user').name)store.each(function(value, key) {    console.log(key, value)})// user { name: 'sun', age: 29 }store.clearAll()  // 清除所有console.log(store.get('user'))  // undefinedconst store = require('store')store.addPlugin(require('store/plugins/expire'))// 一定要加载插件,否则key永远不会过期let d = new Date()store.set('user', 'sun', (new Date()).getTime() + (5 * 1000))  // 注意时间单位setInterval(() => console.log(store.get('user', 'abc')), 1000)

 1.4 Mobx状态管理

社区提供的状态管理库,有ReduxMobx。Redux代码优秀,使用严格的函数式编程思想,学习曲线陡峭,小项目使用的优势不明显。 Mobx,非常优秀稳定的库,简单方便,适合中小项目使用。使用面向对象的方式,容易学习和接受。现在在中小 项目中使用也非常广泛。MobxReact也是一对强力组合。

Mobx官网 https://mobx.js.org/

中文网 http://cn.mobx.js.org/

MobX 是由 MendixCoinbaseFacebook 开源,它实现了观察者模式。

观察者模式,也称为发布订阅模式,观察者观察某个目标,目标对象(Obserable)状态发生了变化,就会通知自己内部注册了的观察者Observer

状态管理 :

需求 :一个组件的onClick触发事件响应函数,此函数会调用后台服务。但是后台服务比较耗时,等处理完,需要引起组

件的渲染操作。要组件渲染,就需要改变组件的propsstate

异步调用:思路一、使用setTimeout ,使用setTimeout,有2个问题。

  • 无法向内部的待执行函数传入参数,比如传入Root实例。
  • 延时执行的函数的返回值无法取到,所以无法通知Root

思路二、Promise异步执行:Promise异步执行,如果成功执行,将调用回调。

import React from 'react';import ReactDom from 'react-dom';class Service {    handle(obj) {        // Promise        new Promise((resolve, reject) => {            setTimeout(() => resolve('OK'), 5000);        }).then(            value => { // 使用obj                obj.setState({                    ret: (Math.random() * 100)                });            }        )    }}class Root extends React.Component {    state = {        ret: null    }    handleClick(event) {        // 异步不能直接使用返回值        this.props.service.handle(this);    }    render() {        console.log('***********************');        return ( 
{ new Date().getTime() } Service中修改state的值是: { this.state.ret }
); }}ReactDom.render( < Root service = {new Service()}/>, document.getElementById('root'));

不管render中是否显示state的值,只要state改变,都会触发render执行。

Mobx实现 :

observable装饰器:设置被观察者

observer装饰器:设置观察者,将React组件转换为响应式组件

import React from 'react';import ReactDom from 'react-dom';import {    observable} from 'mobx';import {    observer} from 'mobx-react';class Service {    @observable ret = -100;    handle() {        // Promise        new Promise((resolve, reject) => {            setTimeout(() => resolve('OK'), 2000);        }).then(            value => {                this.ret = (Math.random() * 100);                console.log(this.ret);            }        )    }}@observer // 将react组件转换为响应式组件class Root extends React.Component {    //state = {ret:null} // 不使用state了    handleClick(event) {        // 异步不能直接使用返回值        this.props.service.handle(this);    }    render() {        console.log('***********************');        return ( 
{ new Date().getTime() } Service中修改state的值是: { this.props.service.ret }
); }}ReactDom.render( < Root service = {new Service()}/>, document.getElementById('root'));

Service中被观察者ret变化,导致了观察者调用了render函数。被观察者变化不引起渲染的情况:将上例中的 {this.props.service.ret} 注释 {/*this.props.service.ret*/} 。可以看到,如果在render中不使用这个被观察者,render函数就不会调用。在观察者的render函数中,一定要使用这个被观察对象。

跳转:如果serviceret发生了变化,观察者Login就会被通知到。一般来说,就会跳转到用户界面,需要使用Redirect

件。

// 导入Redirectimport {Link, Redirect} from 'react-router-dom';//render函数中returnreturn 
; //to表示跳转到哪里

login登录功能代码实现:

import axios from 'axios'import store from 'store'import expire from 'store/plugins/expire'import { observable } from 'mobx';import '../css/login.css'// const store = require('store')// store.addPlugin(require('store/plugins/expire'))  // 这一一定要引一下,否则不会有过期时间store.addPlugin(expire)export default class UserService {    // @observable ret = 0  // 这个值的变化会引起login组件的render    // @observable ret = ''    @observable loggedin = false    @observable errMsg = ''    @observable reged = false;    login(email, password){        // todo        console.log(email, password)        axios.post('/api/users/login', {            email: email,            password: password        }).then(            response => {  {/* 此函数与要解决this的问题,具体参考this的坑 */}                // console.log(response)                console.log(response.data)                console.log(response.status)                // console.log(response.statusText)                let token = response.data.token                store.set('token', token, (new Date()).getTime() + (8 * 3600 * 1000))  // 设置token过期时间                // let ret = Math.random() * 1000 + 1000                // console.log(ret)                // this.ret = response.data.user.name                // console.log(this.ret)                this.loggedin = true            }        ).catch(            error => {  // this的坑                const {error: err=''} = error.response.data  // err是别名                console.log(err)                this.errMsg = err            }        )    }    reg(name, email, password) {        console.log(name, email, password)                axios.post('/api/users/', {            email: email,            password: password,            name: name        }).then(            response => {  {/* 此函数与要解决this的问题,具体参考this的坑 */}                // console.log(response)                console.log(response.data)                console.log(response.status)                // console.log(response.statusText)                let token = response.data.token                store.set('token', token, (new Date()).getTime() + (8 * 3600 * 1000))  // 设置token过期时间                // let ret = Math.random() * 1000 + 1000                // console.log(ret)                // this.ret = response.data.user.name                // console.log(this.ret)                this.reged = true            }        ).catch(            error => {                const {error: err=''} = error.response.data  // err是别名                console.log(err)                this.errMsg = err            }        )    }}const userService = new UserService()export {userService}

 

 

转载地址:http://ztfvi.baihongyu.com/

你可能感兴趣的文章
nginx反代 499 502 bad gateway 和timeout
查看>>
linux虚拟机安装tar.gz版jdk步骤详解
查看>>
python实现100以内自然数之和,偶数之和
查看>>
python数字逆序输出及多个print输出在同一行
查看>>
苏宁产品经理面经
查看>>
百度产品经理群面
查看>>
去哪儿一面+平安科技二面+hr面+贝贝一面+二面产品面经
查看>>
element ui 弹窗在IE11中关闭时闪现问题修复
查看>>
vue 遍历对象并动态绑定在下拉列表中
查看>>
Vue动态生成el-checkbox点击无法选中的解决方法
查看>>
python __future__
查看>>
MySQL Tricks1
查看>>
python 变量作用域问题(经典坑)
查看>>
pytorch
查看>>
pytorch(三)
查看>>
ubuntu相关
查看>>
C++ 调用json
查看>>
nano中设置脚本开机自启动
查看>>
动态库调动态库
查看>>
Kubernetes集群搭建之CNI-Flanneld部署篇
查看>>