部落格專案之前端開發—註冊功能實現
1、前端註冊功能實現
在service/user.js中增加reg註冊函式
1 import axios from "axios" 2 import { observable } from "mobx"; 3 import store from 'store' 4 5 // 過期外掛 6 store.addPlugin(require('store/plugins/expire')) 7 8 class UserService { 9 // 定義被觀察物件 10 @observable loggedin = false 11 12 //登入 13 login (email, password) { 14 //TODO 15 console.log('----------------') 16 console.log(email) 17 console.log(password) 18 console.log('----------------') 19 20 axios.post('/api/user/login', { 21 email:email, 22 password:password23 })// 成功執行 24 // 普通函式,用箭頭處理this問題 25 .then((response) => { 26 console.log(1,response); 27 console.log(2,response.data) 28 const {token, user} = response.data 29 console.log(3,token) 30 store.set('token',token, (newDate()).getTime() + (8 * 3600 * 1000)) 31 console.log(4,user) 32 //成功後,狀態改變 33 this.loggedin = true 34 35 })//錯誤就不執行 36 .catch( (error) => { 37 console.log(7,error); 38 this.loggedin = false; 39 }); 40 } 41 42 // 註冊 43 reg (name, email, password) { 44 //TODO 45 console.log('-------***---------') 46 console.log(email) 47 console.log(password) 48 console.log('-------***---------') 49 50 axios.post('/api/user/reg', { 51 email:email, 52 password:password, 53 name:name 54 })// dev server 會代理 55 // 普通函式,用箭頭處理this問題 56 .then( response => { 57 console.log(1,response); 58 console.log(2,response.data) 59 console.log(3,response.status) 60 const {token, user} = response.data 61 console.log(4,token) 62 // 儲存token 63 store.set('token',token, (new Date()).getTime() + (8 * 3600 * 1000)) 64 console.log(5,user) 65 //成功後,狀態改變 66 console.log('==================') 67 this.loggedin = true 68 console.log('==================') 69 70 })//錯誤就不執行 71 .catch(error => { 72 console.log(6,error); 73 this.loggedin = false; 74 }); 75 } 76 } 77 78 79 80 //全域性變數 81 const userService = new UserService() 82 83 export {userService}
《===等價===》
測試:
component/reg.js 元件:
1 import React from 'react' 2 import{Link, Redirect} from 'react-router-dom' 3 import '../css/login.css' 4 import {userService as service} from '../service/user'; 5 import { observer } from 'mobx-react'; 6 7 8 9 export default class Reg extends React.Component{ 10 render(){ 11 return <_Reg service={service} />; 12 } 13 } 14 // 觀察者 15 @observer 16 class _Reg extends React.Component{ 17 validatePwd(pwd1, pwd2) { 18 return pwd1.value == pwd2.value //確保兩次輸入的密碼一致,下面沒有程式碼,可以自己新增 19 } 20 21 handleClick(event) { 22 event.preventDefault() 23 console.log(typeof(event.target.form),'=========') 24 const [name, email, password, confirm] = event.target.form; 25 console.log(this.validatePwd(password, confirm),'===========') 26 this.props.service.reg(name.value, email.value, password.value); 27 28 } 29 30 render(){ 31 if (this.props.service.loggedin) { 32 return <Redirect to="/" /> 33 } 34 return( 35 <div className="login-page"> 36 <div className="form"> 37 <form className="register-form"> 38 <input type="text" placeholder="姓名"/> 39 <input type="text" placeholder="郵箱"/> 40 <input type="password" placeholder="密碼"/> 41 <input type="password" placeholder="確認密碼"/> 42 <button onClick={this.handleClick.bind(this)}>註冊</button> 43 <p className="message">已經註冊? <Link to="/login">登入</Link></p> 44 </form> 45 </div> 46 </div> 47 ) 48 } 49 }
1 # 註冊(業務) insert 2 def reg(request:HttpRequest): 3 try: 4 play = simplejson.loads(request.body) 5 # print(play, type(play),'========================') 6 email = play["email"] 7 a = User.objects.filter(email=email) 8 # print(a.query) # 檢視查詢語句 9 if a.first():# 懶惰,只要用,就會查 10 return HttpResponseBadRequest('使用者名稱存在') 11 print('--------------------------------------') 12 name = play["name"] 13 # 這兩步可以合起來,減少計算 14 password = play["password"] 15 print(password) 16 password = bcrypt.hashpw(password.encode(), bcrypt.gensalt()) 17 # ORM 操作 18 user = User() 19 user.email = email 20 user.name = name 21 user.password = password 22 23 try: # 這個try可以去掉,不要把e法到瀏覽器端, 24 # 這個try裡可以做些特殊處理; 25 user.save() # commit提交 26 # 如果正常,返回json資料 27 token = gen_token(user.id) 28 res = JsonResponse({ 29 'user': { 30 "user_id": user.id, 31 "name": user.name, 32 "email": user.email 33 }, 34 'token': token 35 }) 36 res.set_cookie('Jwt', token) # set cookie 37 return res 38 except jwt.ExpiredSignatureError as e: 39 print(e) 40 return HttpResponseBadRequest("jwt 過期了") 41 except Exception as e: 42 print(e) 43 # return HttpResponseBadRequest("引數錯誤") 44 raise # 直接往外拋,外面的接住。 45 except Exception as e: # 有任何異常返回。 46 print(e,'==') 47 return HttpResponseBadRequest("引數錯誤") # 這裡返回例項,這不是異常類,繼承自httpresponse後臺user/reg.py
注意:
所有的業務操作都是對一個service例項的操作,不能說,註冊使用一個service例項,登入使用一個service例項,這樣兩者沒有任何關係
所以直接從service/user.js 中匯出,為每個業務使用
本專案是:只要註冊成功,就不需要登入了,直接登入成功,所以後臺直接返回token
2、Ant Design
Ant Design 螞蟻金服開源的 React UI 庫
官網:https://ant.design/index-cn
官方文件:https://ant.design/docs/react/introduce-cn
安裝: $npm install antd $ yarn add antd
使用:
3、網頁中資訊顯示
網頁開發中,不管操作成功與否,有很多資訊提示, 目前資訊都是控制檯輸出的,使用者看不到,使用Antd的message元件顯示友好資訊提示
在service/user.js 中增加一個被觀察物件
1 import axios from "axios" 2 import { observable } from "mobx"; 3 import store from 'store' 4 5 6 // 過期外掛 7 store.addPlugin(require('store/plugins/expire')) 8 9 class UserService { 10 // 定義被觀察物件 11 @observable loggedin = false 12 @observable errMsg = '' // 登入錯誤資訊 13 14 //登入 15 login (email, password) { 16 //TODO 17 console.log('----------------') 18 console.log(email) 19 console.log(password) 20 console.log('----------------') 21 22 axios.post('/api/user/login', { 23 email:email, 24 password:password 25 })// 成功執行 26 // 普通函式,用箭頭處理this問題 27 .then((response) => { 28 console.log(1,response); 29 console.log(2,response.data) 30 const {token, user} = response.data 31 console.log(3,token) 32 store.set('token',token, (new Date()).getTime() + (8 * 3600 * 1000)) 33 console.log(4,user) 34 //成功後,狀態改變 35 this.loggedin = true 36 this.errMsg = '' 37 38 })//錯誤就不執行 39 .catch( (error) => { 40 console.log(7,error); 41 this.loggedin = false; 42 this.errMsg = '登入名或密碼錯誤' 43 }); 44 } 45 46 // 註冊 47 reg (name, email, password) { 48 //TODO 49 console.log('-------***---------') 50 console.log(email) 51 console.log(password) 52 console.log('-------***---------') 53 54 axios.post('/api/user/reg', { 55 email, 56 password, 57 name 58 })// dev server 會代理 59 // 普通函式,用箭頭處理this問題 60 .then( response => { 61 console.log(1,response); 62 console.log(2,response.data) 63 console.log(3,response.status) 64 const {token, user} = response.data 65 console.log(4,token) 66 // 儲存token 67 store.set('token',token, (new Date()).getTime() + (8 * 3600 * 1000)) 68 console.log(5,user) 69 //成功後,狀態改變 70 console.log('==================') 71 this.loggedin = true 72 this.errMsg = ' ' 73 console.log('==================') 74 75 })//錯誤就不執行 76 .catch(error => { 77 console.log(6,error); 78 this.loggedin = false; 79 this.errMsg = '註冊失敗' 80 81 }); 82 } 83 } 84 85 86 87 //全域性變數 88 const userService = new UserService() 89 90 export {userService}
component/login.js元件,增加Antd的message元件
1 import React from 'react'; 2 import {Link,Redirect} from 'react-router-dom'; 3 import '../css/login.css'; 4 import {userService as service} from '../service/user'; 5 import { observer } from 'mobx-react'; 6 import { message } from 'antd' 7 import 'antd/lib/message/style' 8 9 10 11 12 export default class Login extends React.Component{ 13 render(){ 14 return <_Login service={service} />; 15 } 16 } 17 // 觀察者 18 @observer 19 class _Login extends React.Component { 20 handleClick(event) { 21 event.preventDefault(); 22 const [email, password] = event.target.form 23 this.props.service.login(email.value, password.value)// 獲取表單的值 24 } 25 26 27 render(){ 28 console.log('======================') 29 // 觀察者發現改變了,在這裡只要用一次,即便是列印,就會通知render 30 // 沒有改變,則不會被呼叫loggedin 31 console.log(this.props.service.loggedin) 32 // 登入成功之後,就不會往下走了,直接return,並跳轉 33 if (this.props.service.loggedin) return <Redirect to="/" /> 34 //import { message } from 'antd' 35 // 官網提供的函式:顯示3秒資訊,之後,置空 36 if (this.props.service.errMsg) {// 如果註冊失敗,才會進來 37 //js中 [] {} 等效true 38 message.info(this.props.service.errMsg, 3, 39 () => this.props.service.errMsg = '') 40 } 41 42 return( 43 <div className="login-page"> 44 <div className="form"> 45 <form className="login-form"> 46 <input type="text" placeholder="郵箱"/> 47 <input type="password" placeholder="密碼"/> 48 <button onClick={this.handleClick.bind(this)}>登入</button> 49 <p className="message">未註冊? <a href="#">立即註冊</a></p> 50 {/* <span>{this.props.service.errMsg}</span> */} 51 </form> 52 </div> 53 </div> 54 ) 55 } 56 }
結果:
上面的程式碼執行到使用者登入失敗的時候,瀏覽器控制檯會丟擲 一個警告:
解決辦法:
將訊息的清除程式碼移動到 componentDidUpdat中(render結束後執行 訊息提示)
1 import React from 'react'; 2 import {Link,Redirect} from 'react-router-dom'; 3 import '../css/login.css'; 4 import {userService as service} from '../service/user'; 5 import { observer } from 'mobx-react'; 6 import { message } from 'antd' 7 import 'antd/lib/message/style' 8 9 10 11 12 export default class Login extends React.Component{ 13 render(){ 14 return <_Login service={service} />; 15 } 16 } 17 // 觀察者 18 @observer 19 class _Login extends React.Component { 20 handleClick(event) { 21 event.preventDefault(); 22 const [email, password] = event.target.form 23 this.props.service.login(email.value, password.value)// 獲取表單的值 24 } 25 26 27 render(){ 28 console.log('======================') 29 // 觀察者發現改變了,在這裡只要用一次,即便是列印,就會通知render 30 // 沒有改變,則不會被呼叫loggedin 31 console.log(this.props.service.loggedin) 32 // 登入成功之後,就不會往下走了,直接return,並跳轉 33 if (this.props.service.loggedin) return <Redirect to="/" /> 34 35 let em = this.props.service.errMsg; // 引用這個值,留作觀察,否則不知道時候改了沒 36 37 return( 38 <div className="login-page"> 39 <div className="form"> 40 <form className="login-form"> 41 <input type="text" placeholder="郵箱"/> 42 <input type="password" placeholder="密碼"/> 43 <button onClick={this.handleClick.bind(this)}>登入</button> 44 <p className="message">未註冊? <a href="#">立即註冊</a></p> 45 {/* <span>{this.props.service.errMsg}</span> */} 46 </form> 47 </div> 48 </div> 49 ) 50 } 51 componentDidUpdate(prevProps, prevState) { //渲染後,顯示訊息元件 52 //這裡的prevProps和下面的this.props是同一個值,因為service這個屬性沒有改變 53 //一直是user。js中匯出的service 54 //import { message } from 'antd' 55 // 官網提供的函式:顯示3秒資訊,之後,置空 56 if (prevProps.service.errMsg) {// 如果註冊失敗,才會進來 57 //js中 [] {} 等效true 58 message.info(prevProps.service.errMsg, 3, 59 () => prevProps.service.errMsg = '') 60 } 61 } 62 }
component/reg.js元件同樣增加message元件
1 import React from 'react' 2 import{Link, Redirect} from 'react-router-dom' 3 import '../css/login.css' 4 import {userService as service} from '../service/user'; 5 import { observer } from 'mobx-react'; 6 import { message } from 'antd' 7 import 'antd/lib/message/style' 8 import {inject} from '../utils' 9 10 11 12 // 觀察者 13 @inject({service}) 14 @observer 15 class _Reg extends React.Component{ 16 validatePwd(pwd1, pwd2) { 17 return pwd1.value == pwd2.value 18 } 19 validateEma(email) { 20 // email校驗 21 } 22 23 handleClick(event) { 24 event.preventDefault() 25 console.log(typeof(event.target.form),'=========') 26 const [name, email, password, confirm] = event.target.form; 27 if (this.validatePwd(password, confirm) ){ 28 this.props.service.reg(name.value, email.value, password.value); 29 30 } 31 else { 32 console.log('兩次密碼不同') 33 this.props.service.reg(name.value, email.value, password.value,false); 34 } 35 36 37 } 38 39 render(){ 40 if (this.props.service.loggedin) { 41 return <Redirect to="/" /> 42 } 43 let em = this.props.service.errMsg; // 引用這個值,留作觀察,否則不知道時候改了沒 44 45 return( 46 <div className="login-page"> 47 <div className="form"> 48 <form className="register-form"> 49 <input type="text" placeholder="姓名"/> 50 <input type="text" placeholder="郵箱"/> 51 <input type="password" placeholder="密碼"/> 52 <input type="password" placeholder="確認密碼"/> 53 <button onClick={this.handleClick.bind(this)}>註冊</button> 54 <p className="message">已經註冊? <Link to="/login">登入</Link></p> 55 </form> 56 </div> 57 </div> 58 ) 59 } 60 componentDidUpdate(prevProps, prevState) { //渲染後,顯示訊息元件 61 //這裡的prevProps和下面的this.props是同一個值,因為service這個屬性沒有改變 62 //一直是user。js中匯出的service 63 //import { message } from 'antd' 64 // 官網提供的函式:顯示3秒資訊,之後,置空 65 if (prevProps.service.errMsg) {// 如果註冊失敗,才會進來 66 //js中 [] {} 等效true 67 message.info(prevProps.service.errMsg, 3, 68 () => prevProps.service.errMsg = '') 69 } 70 } 71 }
4、高階元件裝飾器
裝飾器函式的整個過程演變如下:
1 export default class Login extends React.Component{ 2 render(){ 3 return <_Login service={service} />; 4 } 5 } 6 7 class Login extends React.Component{ 8 render(){ 9 return <_Login service={service} />; 10 } 11 } 12 // 匿名 元件 13 const Login = class extends React.Component { 14 render(){ 15 return <_Login service={service} />; 16 } 17 } 18 // 提引數 19 function inject (){ 20 return Login 21 } 22 23 function inject() { 24 return class extends React.Component { 25 render(){ 26 return <_Login service={service} />; 27 } 28 } 29 } 30 31 function inject(x,Comp) { 32 return class extends React.Component { 33 render(){ 34 return <Comp service={x} />; 35 } 36 } 37 } 38 39 //柯里化 40 function inject(x) { 41 function wrapper (Comp) { 42 return class extends React.Component { 43 render(){ 44 return <Comp service={x} />; 45 } 46 } 47 } 48 return wrapper 49 } 50 51 52 53 function inject(obj) { 54 function wrapper (Comp) { 55 return class extends React.Component { 56 render(){ 57 return <Comp {...obj} /> 58 } 59 } 60 } 61 return wrapper 62 } 63 64 function inject(obj) { 65 return wrapper (Comp) { 66 return class extends React.Component { 67 render(){ 68 return <Comp {...obj} /> 69 } 70 } 71 } 72 } 73 74 const inject = obj => Comp => { 75 return class extends React.Component { 76 render(){ 77 return <Comp {...obj} /> 78 } 79 } 80 } 81 //等價為一個無狀態元件 82 const inject = obj => Comp => { 83 return function (props) { 84 return <Comp {...obj} /> 85 } 86 } 87 88 89 const inject = obj => Comp => { 90 props => <Comp {...obj} />; 91 } 92 93 const inject = obj => Comp => props => <Comp {...obj} />; 94 const inject = obj => Comp => props => <Comp {...obj} {...props} />;
新建一個工具檔案 src/utils.js 放入以下內容:
1 import React from 'react' 2 3 const inject = obj => Comp => props => <Comp {...obj} {...props} />; 4 5 6 export {inject}
將登入,註冊元件裝飾一下:
具體程式碼:Mobx的observer 裝飾器要求,所以注意裝飾的順序
1 import React from 'react'; 2 import {Link,Redirect} from 'react-router-dom'; 3 import '../css/login.css'; 4 import {userService as service} from '../service/user'; 5 import { observer } from 'mobx-react'; 6 import { message } from 'antd' 7 import 'antd/lib/message/style' 8 import {inject} from '../utils' 9 10 11 @inject({service}) 12 @observer//官方推薦,貼近類 13 export default class Login extends React.Component { 14 handleClick(event) { 15 event.preventDefault(); 16 const [email, password] = event.target.form 17 this.props.service.login(email.value, password.value)// 獲取表單的值 18 } 19 20 21 render(){ 22 console.log('======================') 23 // 觀察者發現改變了,在這裡只要用一次,即便是列印,就會通知render 24 // 沒有改變,則不會被呼叫loggedin 25 console.log(this.props.service.loggedin) 26 // 登入成功之後,就不會往下走了,直接return,並跳轉 27 if (this.props.service.loggedin) return <Redirect to="/" /> 28 29 let em = this.props.service.errMsg; // 引用這個值,留作觀察,否則不知道時候改了沒 30 31 return( 32 <div className="login-page"> 33 <div className="form"> 34 <form className="login-form"> 35 <input type="text" placeholder="郵箱"/> 36 <input type="password" placeholder="密碼"/> 37 <button onClick={this.handleClick.bind(this)}>登入</button> 38 <p className="message">未註冊? <a href="#">立即註冊</a></p> 39 {/* <span>{this.props.service.errMsg}</span> */} 40 </form> 41 </div> 42 </div> 43 ) 44 } 45 componentDidUpdate(prevProps, prevState) { //渲染後,顯示訊息元件 46 //這裡的prevProps和下面的this.props是同一個值,因為service這個屬性沒有改變 47 //一直是user。js中匯出的service 48 //import { message } from 'antd' 49 // 官網提供的函式:顯示3秒資訊,之後,置空 50 if (prevProps.service.errMsg) {// 如果註冊失敗,才會進來 51 //js中 [] {} 等效true 52 message.info(prevProps.service.errMsg, 3, 53 () => prevProps.service.errMsg = '') 54 } 55 } 56 }login.js
1 import React from 'react' 2 import{Link, Redirect} from 'react-router-dom' 3 import '../css/login.css' 4 import {userService as service} from '../service/user'; 5 import { observer } from 'mobx-react'; 6 import { message } from 'antd' 7 import 'antd/lib/message/style' 8 import {inject} from '../utils' 9 10 11 12 // 觀察者 13 @inject({service}) 14 @observer 15 class _Reg extends React.Component{ 16 validatePwd(pwd1, pwd2) { 17 return pwd1.value == pwd2.value 18 } 19 validateEma(email) { 20 // email校驗 21 } 22 23 handleClick(event) { 24 event.preventDefault() 25 console.log(typeof(event.target.form),'=========') 26 const [name, email, password, confirm] = event.target.form; 27 if (this.validatePwd(password, confirm) ){ 28 this.props.service.reg(name.value, email.value, password.value); 29 30 } 31 else { 32 console.log('兩次密碼不同') 33 this.props.service.reg(name.value, email.value, password.value,false); 34 } 35 36 37 } 38 39 render(){ 40 if (this.props.service.loggedin) { 41 return <Redirect to="/" /> 42 } 43 let em = this.props.service.errMsg; // 引用這個值,留作觀察,否則不知道時候改了沒 44 45 return( 46 <div className="login-page"> 47 <div className="form"> 48 <form className="register-form"> 49 <input type="text" placeholder="姓名"/> 50 <input type="text" placeholder="郵箱"/> 51 <input type="password" placeholder="密碼"/> 52 <input type="password" placeholder="確認密碼"/> 53 <button onClick={this.handleClick.bind(this)}>註冊</button> 54 <p className="message">已經註冊? <Link to="/login">登入</Link></p> 55 </form> 56 </div> 57 </div> 58 ) 59 } 60 componentDidUpdate(prevProps, prevState) { //渲染後,顯示訊息元件 61 //這裡的prevProps和下面的this.props是同一個值,因為service這個屬性沒有改變 62 //一直是user。js中匯出的service 63 //import { message } from 'antd' 64 // 官網提供的函式:顯示3秒資訊,之後,置空 65 if (prevProps.service.errMsg) {// 如果註冊失敗,才會進來 66 //js中 [] {} 等效true 67 message.info(prevProps.service.errMsg, 3, 68 () => prevProps.service.errMsg = '') 69 } 70 } 71 }reg.js
@inject({service}) // Reg=inject({service})(Reg) props是Login元件自己的 屬性props