需求:前端
咱們在點擊推薦課程的時候,會有該推薦課程的詳細頁面vue
思路:python
爲每個推薦課程標籤添加事件,從新向後臺請求數據加載頁面,可是url不會發生改變jquery
使用router-link,由於都在在detail路由中,頁面不會從新加載,因此只要url改變,頁面不改變ios
須要說明的是,vue跟jquery不一樣,由於vue是單頁面,全部他作的只是頁面組件的重建與銷燬vuex
如若你只是改變路由的話,那麼頁面不會有變化.npm
若是你只是改變組件那麼路由不會發生變化.django
咱們開發的時候須要兩個一塊兒改變json
<template> <div> <h1>課程詳細頁面</h1> <div> <p>{{detail.course}}</p> <p>{{detail.img}}</p> <p>{{detail.level}}</p> <p>{{detail.slogon}}</p> <p>{{detail.title}}</p> <p>{{detail.why}}</p> <div> <ul v-for="item in detail.chapter"> <li>{{item.name}}</li> </ul> </div> <div> <h3>推薦課程</h3> <ul v-for="item in detail.recommends"> <!--<li><router-link :to="{name:'detail',params:{id:item.id}}">{{item.title}}</router-link></li>--> <li @click="changeDetail(item.id)">{{item.title}}</li> </ul> </div> </div> </div> </template> <script> export default { name: "index", data() { return { detail:{ course:null, img:null, level:null, slogon:null, title:null, why:null, chapter:[], recommends:[], } } }, mounted(){ var id = this.$route.params.id this.initDetail(id) }, methods:{ initDetail(nid){ var that = this this.$axios.request({ url:'http://127.0.0.1:8000/api/v1/course/'+ nid +'/', method:'GET' }).then(function (arg) { if(arg.data.code === 1000){ that.detail = arg.data.data }else{ alert(arg.data.error) } }) }, changeDetail(id){ this.initDetail(id) this.$router.push({name:'detail',params:{id:id}}) } } } </script> <style scoped> </style>
vue中跳轉路徑方法補充:axios
this.$router.push({name:'detail',params:{id:id}})
用戶登陸
需求:
思路:
前端登陸頁面
Login.vue
<template> <div> <h1>用戶登陸</h1> <div> <p> <input type="text" placeholder="請輸入用戶名" v-model="username"> </p> <p> <input type="password" placeholder="請輸入密碼" v-model="password"> </p> <input type="button" value="登陸" @click="doLogin"> </div> </div> </template> <script> export default { data() { return { username:'', password:'' } }, methods:{ doLogin(){ var that = this this.$axios.request({ url:'http://127.0.0.1:8000/api/v1/auth/', method:'POST', data:{ user:this.username, pwd:this.password }, headers:{ 'Content-Type':'application/json', } }).then(function (arg) { if (arg.data.code === 1000){ that.$store.commit('saveToken',{token:arg.data.token,username:that.username}) }else{ alert(arg.data.error) } }).catch(function (arg) { console.log('發生錯誤') }) } } } </script> <style scoped> </style>
store目錄下的store.vue
import Vue from 'vue'
import Vuex from 'vuex'
import Cookie from 'vue-cookies'
Vue.use(Vuex)
export default new Vuex.Store({
// 組件中經過 this.$store.state.username 調用
state: {
username: Cookie.get("username"), #store每次都從cookie中取值
token:Cookie.get("token"),
},
mutations: {
// 組件中經過 this.$store.commit(saveToken,參數) 調用
saveToken: function (state, userToken) {
state.username = userToken.username;
state.token = userToken.token;
Cookie.set("username", userToken.username, "20min")
Cookie.set("token", userToken.token, "20min")
},
clearToken: function (state) {
state.username = null
state.token = null
Cookie.remove('username')
Cookie.remove('token')
}
}
})
在store中,使用vue設置全局變量,vue-cookies保存全局變量,使其刷新後仍然存在於vue-cookies中
vuex全局變量的用法
一、建立store.js
二、main.js中
import store from './store/store' 放到實例化裏邊
組建中能夠經過this.$store.state.username調用
vue-cookies的下載和使用
下載
npm install vue-cookis --save
使用:
若是登陸成功,調用store的mutations方法:
關於向後臺發送數據的簡單請求和複雜請求
條件:
一、請求方式:HEAD、GET、POST
二、請求頭信息:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type 對應的值是如下三個中的任意一個
application/x-www-form-urlencoded
multipart/form-data
text/plain
注意:同時知足以上兩個條件時,則是簡單請求,不然爲複雜請求
若是是複雜請求,那麼就會先發一個options請求到服務裏進行'預檢'
詢問服務器是否容許我用post請求進行訪問.若是是options請求過來後,
給他加上一個特殊的請求頭,那麼就能夠經過了
class CORSMiddleware(MiddlewareMixin): def process_response(self,request,response): # 添加響應頭 # 容許你的域名來獲取個人數據 # response['Access-Control-Allow-Origin'] = "*" # 容許你攜帶Content-Type請求頭 # response['Access-Control-Allow-Headers'] = "Content-Type" # 容許你發送DELETE,PUT # response['Access-Control-Allow-Methods'] = "DELETE,PUT" response['Access-Control-Allow-Origin'] = "*" if request.method == "OPTIONS": response['Access-Control-Allow-Headers'] = "Content-Type" response['Access-Control-Allow-Methods'] = "PUT,DELETE" return response
使用中間件爲每次請求添加響應頭
後端登陸操做
models.py中
class UserInfo(models.Model): '''用戶表''' username=models.CharField(verbose_name='用戶名',max_length=32) password=models.CharField(verbose_name='密碼',max_length=64) nikname=models.CharField(max_length=32,verbose_name='暱稱') def __str__(self): return self.nikname class Token(models.Model): user=models.OneToOneField('UserInfo',on_delete=models.CASCADE,verbose_name='用戶') token=models.CharField(max_length=128) def __str__(self): return self.user
url.py
url(r'^auth/$', account.AuthView.as_view()),
view.py中
from rest_framework.views import APIView
from rest_framework.response import Response
from django.shortcuts import HttpResponse
from api import models
import uuid
class AuthView(APIView): def post(self,request,*args,**kwargs): """ 用戶登陸認證 :param request: :param args: :param kwargs: :return: """ ret = {'code':1000} user = request.data.get('user') pwd = request.data.get('pwd') user = models.UserInfo.objects.filter(user=user,pwd=pwd).first() if not user: ret['code'] = 1001 ret['error'] = '用戶名或密碼錯誤' else: uid = str(uuid.uuid4()) models.UserToken.objects.update_or_create(user=user,defaults={'token':uid}) ret['token'] = uid return Response(ret)
vue-攔截器
用攔截器實現的功能:
在須要登陸才能訪問的頁面,若是未登陸訪問就攔截下來,跳轉到登陸頁面
登陸成功後再跳到訪問的頁面
一、在路徑中添加 meta
{ path: '/news', name: 'news', component: News, meta:{ requireAuth:true } },
二、main.js中
router.beforeEach(function (to, from, next) { if(to.meta.requireAuth){ // 要去的url只有登錄成功後才能訪問 if (store.state.token) { next() #next表示去訪問,原本是去哪訪問就去哪訪問 } else { next({name: 'login',query: {backUrl: to.fullPath}}) } }else{ next() } })
三、login中作判斷,跳轉url
}).then(function (arg) { if (arg.data.code === 1000){ that.$store.commit('saveToken',{token:arg.data.token,username:that.username}) var url = that.$route.query.backUrl if(url){ that.$router.push({path:url}) }else{ that.$router.push({path:'/index'}) }
後端認證
用戶獲取到後端接口,直接不登陸訪問後端的接口,
若是後端沒有認證的話,那麼接口的內容就會被暴露
Micro.vue
<template> <div> <h1>LuffyX學位:{{title}}</h1> </div> </template> <script> export default { name: "index", data() { return { title:null } }, mounted(){ this.initMicro() }, methods:{ initMicro(){ var that = this this.$axios.request({ url:'http://127.0.0.1:8000/api/v1/micro/', method:'GET', params:{ token:this.$store.state.token } }).then(function (arg) { if(arg.data.code === 1000){ that.title = arg.data.title } }) } } } </script> <style scoped> </style>
url.py
url(r'^micro/$', course.MicroView.as_view()),
auth認證
from rest_framework.authentication import BaseAuthentication from rest_framework.exceptions import AuthenticationFailed from api import models class LuffyAuth(BaseAuthentication): def authenticate(self, request): token = request.query_params.get('token') obj = models.UserToken.objects.filter(token=token).first() if not obj: raise AuthenticationFailed({'code':1001,'error':'認證失敗'}) return (obj.user.user,obj)
view.py中使用
class MicroView(APIView): authentication_classes = [LuffyAuth,] def get(self,request,*args,**kwargs): ret = {'code':1000,'title':'微職位'} return Response(ret)
API的統一存放
當你寫了不少API後,你就會發現你本身不知道寫了哪些路由,
那麼若是有人問你要接口的時候你可能會找好久.那麼咱們將api的路由
統一放到vue的store裏
放在api的store裏有什麼好處?
const store = new Vuex.Store({ state: { apiList:{ Course:'http://127.0.0.1:8000/api/v2/course/', CourseDetail:'http://127.0.0.1:8000/api/v2/course/', Login:'http://127.0.0.1:8000/api/v2/login/', Micro:'http://127.0.0.1:8000/api/v2/micro/', } },