一、Vuex
1、介紹
vuex是一個專門為Vue.js設計的集中式狀態管理架構。 對於狀態,我們把它理解為在data中需要共享給其他組件使用的部分數據。 Vuex和單純的全局對象有以下不同: 1. Vuex 的狀態存儲是響應式的。當vue組件從store中讀取狀態的時候, 若store中的狀態發生變化,那么相應的組件也會相應的得到高效更新。 2. 你不能直接改變store中的狀態。改變store中的狀態的唯一途徑就是顯示的 提交(commit)mutation。這樣使得我們可以方便的跟蹤每一個狀態的變化, 從而讓我們能夠實現一些工具來幫助我們更好的了解我們的應用。
2、vuex的安裝和實例化
1. 安裝命令
-- npm install vuex
2. 實例化的兩種方式

方式一:直接在main.js里面注冊vuex的倉庫實例 // main.js import Vue from 'vue' import App from './App' import Vuex from 'vuex' // 讓vue實例使用Vuex Vue.use(Vuex) Vue.config.productionTip = false // 實例化Vuex的倉庫,store代表倉庫 const store = new Vuex.Store({ // state存放所有的公用數據 state: { name : "bdyjy", } }); new Vue({ el: '#app', // 注冊store: store store, components: { App }, template: '<App/>' });

方式二:為了方便維護,通常在src下面新建一個store文件夾,然后在里面新建一個index.js // store/index.js import Vuex from "vuex" import Vue from "vue" Vue.use(Vuex); // 拋出實例化的Vuex倉庫,store代表倉庫 export default new Vuex.Store({ // state存放所有的公用數據 state: { name : "bdyjy", } }) // main.js import Vue from 'vue' import App from './App' import store from "./store/index" Vue.config.productionTip = false new Vue({ el: '#app', // 注冊store: store store, components: { App }, template: '<App/>' });
3、獲取數據
1. state
state是保存我們data中需要共享的數據。 由於Vuex的存儲是響應式的,從store實例中讀取狀態可以使用:this.$store.state.變量名 且應該在計算屬性中返回某個狀態,因為計算屬性實時在監聽數據,數據變化了,它立刻就能知道, 如果在data屬性中返回某個狀態,那么這個數據如果在后續變化了,它也不知道了,因為data在加載完成后就不會再監聽這個數據 示例:在某個組件中使用 // course.vue <template> <div> <h2>這是課程組件</h2> <p>我是{{name}}</p> </div> </template> <script> export default { name: "Course", // 使用計算屬性獲取倉庫里面的name變量的值 computed: { name: function () { return this.$store.state.name } } } </script>
2. getters
有時候我們需要從store中的state中派生出一些狀態,例如對數據進行簡單的計算。
並且很多組件都需要用到此方法,我們要么復制這個函數,要么抽取到一個公共函數,多處導入。
我們vuex提供了更加方便的方法,getters 它就像計算屬性一樣,getters的返回值會根據它的依賴被
緩存起來,只有它的依賴發生改變時,才會重新計算。
簡單地來說,getters可以對狀態進行二次處理

1. // store/index.js import Vuex from "vuex" import Vue from "vue" Vue.use(Vuex); // 拋出實例化的Vuex倉庫,store代表倉庫 export default new Vuex.Store({ // state存放所有的公用數據 state: { name : "bdyjy", }, // getters對state的值進行二次處理 getters: { friend: function (state) {// 接收state作為參數 return state.name + '的朋友是:jty' } } }) 2. // 在某個組件中使用 // course.vue <template> <div> <h2>這是課程組件</h2> <p>我是{{name}}</p> <p>{{friend}}</p> </div> </template> <script> export default { name: "Course", computed: { name: function () {// 通過state取值 return this.$store.state.name }, friend: function () {// 通過getters取值 return this.$store.getters.friend } } } </script>

1. // store/index.js import Vuex from "vuex" import Vue from "vue" Vue.use(Vuex); // 拋出實例化的Vuex倉庫,store代表倉庫 export default new Vuex.Store({ // state存放所有的公用數據 state: { name : "bdyjy", }, // getters對state的值進行二次處理 getters: { friend: function (state) {// 接收state作為參數 return state.name + '的朋友是:jty' }, play: function (state, getters) {// 接收state和getters作為參數 // 因為要取到friend,就要state return getters.friend + '一起玩' } } }) 2. // 在某個組件中使用 // course.vue <template> <div> <h2>這是課程組件</h2> <p>我是{{name}}</p> <p>{{friend}}</p> <p>{{play}}</p> </div> </template> <script> export default { name: "Course", computed: { name: function () {// 通過state取值 return this.$store.state.name }, friend: function () {// 通過getters取值 return this.$store.getters.friend }, play: function () { return this.$store.getters.play } } } </script>
4、更改store中的狀態
1. 回想一下非父子之間的組件之間是如何進行通信的
-- 新建一個新的vue實例當做兩個組件之間通信的橋梁 -- 一個組件使用 $emit 向這個vue實例提交事件 -- 另一個組件在加載完成后這個vue實例通過鈎子函數mounted 使用 $on 監聽$emit提交的事件然后處理
2. vuex更改store中的狀態類似於上面的步驟
-- 通過this.$store.commit('事件名稱', '數據')提交事件到這個vuex倉庫 -- 在Vuex.Store這個實例里面通過mutations接收提交過來的事件 -- mutations里面的事件它會接收state為第一個參數,后面接收其他參數
3.示例

<template> <div> <h2>這是學位課程信息</h2> <button @click="my_click">點擊展示學位信息</button> <h3>{{degree_info}}</h3> </div> </template> <script> export default { name: "DegreeCourse", computed: { degree_info: function () { return this.$store.state.degree_info } }, methods: { // 提交事件到store my_click: function () { this.$store.commit('degree_info', '博士') } } } </script>

import Vuex from "vuex" import Vue from "vue" Vue.use(Vuex); // 拋出實例化的Vuex倉庫,store代表倉庫 export default new Vuex.Store({ state: { degree_info: '' }, // commit上來的事件在這里進行處理 mutations: { degree_info: function (state, data) { state.degree_info = data } } })
二、axios的簡單使用
1、安裝
使用npm安裝axios -- npm install axios axios是基於promise用於瀏覽器和node.js的http客戶端
2、axios基本參數
url:請求接口地址 method:請求方式 data:請求數據 headers:請求頭 then(function(response){}):請求成功后的回調函數 catch(function(error){})請求失敗后的回調函數

1.發送ajax請求 $.ajax({}) 參數: url: 提交到哪個URL地址 type: 提交的方式 data: {你要發送的數據} success: function (res) { 請求發送過去,被正常響應后執行的函數,res是后端返回來的數據 } error: function (err) { 請求發送過去,響應失敗時執行的函數 } 2.示例 $.ajax({ url: '/regirest/', type: 'POST', data: { username: 'xxx', }, success: function (res) { console.log(res) } })
3、幾種請求方法
1. get請求

// 攜帶參數的get請求 axios.get('/user?ID=12345') .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); });

// 上面的請求可以這樣做 axios.get('/user', { params: { ID: 12345 } }) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); });
2. post請求

axios.post('/user', { username: 'xiaoming', password: '123abcd' }) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); });
3. 執行多個並發請求

function getUserAccount() { return axios.get('/user/12345'); } function getUserPermissions() { return axios.get('/user/12345/permissions'); } axios.all([getUserAccount(), getUserPermissions()]) .then().catch();
4. axios.request(推薦使用這種)

axios.request({ url: '/user/12345', method: 'post', // 請求方式:get、post、delete等等 data: { username: 'xiaoming', password: '123abcd' } }).then(function (response) { console.log(response); }).catch(function (error) { console.log(error) });
4、示例
1. 把axios設置成Vue對象屬性
下載好axios后,在需要使用的地方導入axios即可直接使用,axios類似於ajax,用於向后端進行數據傳輸 但是axios是不能注冊到Vue實例里面,因此不能通過this.$axios進行使用的,因為它不是Vue實例的屬性, 但是我們就是希望能夠通過this.$axios對它進行使用呢,可以給Vue的原型鏈prototype增加一個$axios屬性, 然后所有的Vue對象都可以通過this.$axios對它進行使用 // main.js import axios from "axios" Vue.prototype.$axios = axios
2. Vue代碼

<script> export default { name: "DegreeCourse", mounted(){ this.$axios.request({ url: "http://127.0.0.1:8000/test/", // 后端地址 method: "get" // 提交方式 }).then(function (response) {// then是成功后的回調函數 console.log(response); }).catch(function (error) {// catch是失敗后的回調函數 console.log(error); }) } } </script>
3. 瀏覽器的同源策略
當這個組件加載完后,會自動向后端http://127.0.0.1:8000/test/ 發送 get 請求, 但是這樣發送的請求是屬於跨域請求,由於瀏覽器的同源策略,服務器給我們返回的信息瀏覽器會給我們攔截下來, 所以如果后端返回消息的時候不進行一些處理的話,前端這里是收不到消息的並且會報錯。(前后端的域名和端口只要其中一個不一樣,就是跨域), 跨域的ajax請求就會被瀏覽器攔截(axios發送的也是ajax請求)。 那怎么處理?繼續往下看..
三、CORS跨域請求介紹
1、區分簡單請求和復雜請求
HTTP方法是下列方法之一 HEAD, GET,POST HTTP頭信息不超出以下幾種字段 Accept, Accept-Language, Content-Language, Last-Event-ID Content-Type只能是下列類型中的一個 application/x-www-form-urlencoded multipart/form-data text/plain 任何一個不滿足上述要求的請求,即會被認為是復雜請求 復雜請求會先發出一個預請求,我們也叫預檢,OPTIONS請求 也就是說,HEAD, GET,POST這三個請求,當它們滿足上面的頭信息時,它們就是簡單請求,否則都是復雜請求, 比如一個get請求,但是它請求頭的Content-Type是application/json類型,那么它也是復雜請求。 復雜請求會先發出一個OPTIONS預請求。
2、請求頭
Accept 我能解析什么數據類型 ContentType 我給你的是什么數據類型 數據類型 application/x-www-form-urlencoded --> form表單的默認編碼方式,不能上傳文件 multipart/form-data --> 二進制的形式,能上傳文件 text/plain --> 文本 application/json --> json格式 html xml
四、跨域請求處理--jsonp
1、 原理(現在很少有人使用這種方式處理跨域請求)
我們可以發現,我們使用CDN引進任何鏈接的時候,引進了就可以使用了,但是,CDN的鏈接對於我們來說也是跨域,為什么不會報錯呢?
原因是對於script、link或img這些標簽,他們引入CDN只是發送get請求獲取資源,瀏覽器認為這沒有風險,所以可以正常進行請求,
而ajax可以發送任何類型的請求,風險太大,瀏覽器就自動把它們攔截了(瀏覽器只阻止表單以及ajax請求)。
比如script標簽src想某個CDN發送get請求,拿到的所有資源就會存在script標簽內,你就可以在script標簽內使用這些內容。
2、示例

// 某前端頁面代碼 <script> // 定義一個函數 function handlerResponse(data) { console.log(data) } </script> // 向后端發送請求,拿到handlerResponse函數並執行 <script src="http://127.0.0.1:8000/test/"></script>

// 某Django后端代碼 class TestView(views.View): def get(self, request): # 返回一個handlerResponse("ok")字符串 return HttpResponse('handlerResponse("ok")')
五、CORS跨域請求之簡單請求處理
1、 get跨域簡單請求
1. 報錯原因
Access-Control-Allow-Origin --> 前端這個域不被允許接收后端的數據
2. 后端視圖函數

class TestView(views.View): def get(self, request): return HttpResponse('嘿嘿')
3. 后端中間件

from django.utils.deprecation import MiddlewareMixin class MyCores(MiddlewareMixin): def process_response(self, request, response): # 給這個響應添加響應頭 # 告訴瀏覽器我這個后端允許響應頭指定的域拿到我的響應數據(*代表所有域) response['Access-Control-Allow-Origin'] = '*' # http://localhost:8080代表只能讓這個域拿到我的數據 # response['Access-Control-Allow-Origin'] = 'http://localhost:8080' return response
4. 前端Vue

<script> export default { name: "DegreeCourse", mounted(){ this.$axios.request({ url: "http://127.0.0.1:8000/test/", // 后端地址 method: "get" // get簡單請求 // method: "post" // post簡單請求 }).then(function (response) {// then是成功后的回調函數 console.log(response); // 接收到后端response的數據是一個對象 }).catch(function (error) {// catch是失敗后的回調函數 console.log(error); }) } } </script>
2、 post跨域簡單請求
注意:前后端分離的項目沒辦法提交csrf,有些框架是可以默認過濾跳過這個驗證,現在的話,我們先在后端把csrf中間件注釋掉
代碼跟上面一樣,只是在前端把method的提交方式改成post即可
六、CORS跨域請求之復雜請求處理
1、delete跨域復雜請求
1. 報錯原因
Access-Control-Allow-Methods --> 這個請求方法不被允許
2. 后端視圖函數

class TestView(views.View): def delete(self, request): return HttpResponse("返回DELETE數據")
3. 后端中間件

class MyCores(MiddlewareMixin): def process_response(self, request, response): # 給這個響應添加響應頭 # 告訴瀏覽器我這個后端允許響應頭指定的域拿到我的響應數據(*代表所有域) response['Access-Control-Allow-Origin'] = '*' # http://localhost:8080代表只能讓這個域拿到我的數據 # response['Access-Control-Allow-Origin'] = 'http://localhost:8080' # 如果是復雜請求,會先發送OPTIONS預檢 if request.method == 'OPTIONS': # 如果是復雜請求的方法不被允許,那么就給告訴瀏覽器我允許這個復雜請求 response["Access-Control-Allow-Methods"] = "DELETE" return response
4. 前端Vue

<script> export default { name: "DegreeCourse", mounted(){ this.$axios.request({ url: "http://127.0.0.1:8000/test/", // 后端地址 method: 'delete' // delete復雜請求 }).then(function (response) {// then是成功后的回調函數 console.log(response); // 接收到后端response的數據是一個對象 }).catch(function (error) {// catch是失敗后的回調函數 console.log(error); }); } } </script>
2、post發送復雜請求
1. 報錯原因
Access-Control-Allow-Headers --> 這個請求頭的數據類型不被允許
2. 后端視圖函數

class TestView(views.View): def post(self, request): return HttpResponse("返回POST數據")
3. 后端中間件

class MyCores(MiddlewareMixin): def process_response(self, request, response): # 給這個響應添加響應頭 # 告訴瀏覽器我這個后端允許響應頭指定的域拿到我的響應數據(*代表所有域) response['Access-Control-Allow-Origin'] = '*' # http://localhost:8080代表只能讓這個域拿到我的數據 # response['Access-Control-Allow-Origin'] = 'http://localhost:8080' # 如果是復雜請求,會先發送OPTIONS預檢 if request.method == 'OPTIONS': # 如果是復雜請求的方法不被允許,那么就給告訴瀏覽器我允許這個復雜請求 response["Access-Control-Allow-Methods"] = "DELETE" # 告訴瀏覽器這個請求頭的數據類型我是允許的 response["Access-Control-Allow-Headers"] = "Content-Type" return response
4. 前端Vue

<script> export default { name: "DegreeCourse", mounted(){ this.$axios.request({ url: "http://127.0.0.1:8000/test/", // 后端地址 method: 'post', // post發送復雜請求 contentType: "application/json", data: { "author": "狗屎" } }).then(function (response) {// then是成功后的回調函數 console.log(response); // 接收到后端response的數據是一個對象 }).catch(function (error) {// catch是失敗后的回調函數 console.log(error); }) } } </script>
3、總結
-- 復雜請求什么不被允許,那么我們就在中間件給它設置成是允許的即可 -- 前端拿到的響應數據是一個對象,具體的值存在這個對象的data屬性里面,取值:響應對象.data -- 響應對象還有其他數據: config: {...} data: "后端返回的具體數據" headers: {content-type: "text/html; charset=utf-8"} request: XMLHttpRequest {…} status: 200 statusText: "OK"
七、VUE中import 、export的注意事項
1、導包的問題
1. import引入一個依賴包,不需要相對路徑 示例:import axios from 'axios'; 2. import 引入一個自己寫的js文件,是需要相對路徑的 import AppService from './appService';
2、export import注意事項
""" import什么情況下,要用{}的方式引入, 什么情況下,只需要一個變量就行。 """ 1. 使用export拋出的變量需要用{}進行import引入 # a.js let name = "xiaoming"; let age = 18; export {name, age} # b.js import {name, age} from "./a.js" 2. 使用export default拋出的變量,只需要自己起一個名字就行 # a.js var obj = { name: '狗明' }; export default obj; # b.js import aaa from './a.js'; console.log(aaa.name); // '狗明' 3. 注意 一個js文件中,只能有一個export default,但是可以有多個export