Vuex、axios、跨域請求處理和import/export的注意問題


一、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
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>
示例2

 

 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
    }
  }
})
store/index.js

 

二、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)
            }
        })
對比ajax

 

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);
  });
post請求

 

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)
});
axios.request

 

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>
View Code

 

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")')
某Django后端代碼

 

五、CORS跨域請求之簡單請求處理

1、 get跨域簡單請求

1. 報錯原因
Access-Control-Allow-Origin --> 前端這個域不被允許接收后端的數據

 

2. 后端視圖函數
class TestView(views.View):
    def get(self, request):
        return HttpResponse('嘿嘿')
View Code

 

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
View Code

 

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>
View Code

 

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數據")
View Code

 

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
View Code

 

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>
View Code

 

2、post發送復雜請求

1. 報錯原因
Access-Control-Allow-Headers --> 這個請求頭的數據類型不被允許

 

2. 后端視圖函數
class TestView(views.View):
    def post(self, request):
        return HttpResponse("返回POST數據")
View Code

 

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
View Code

 

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>
View Code

 

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM