跨域基礎
跨域:
1、是什么
你的目標和你自己現在的位置一樣還是不一樣
瀏覽器上的同源策略
特點:
1、跨域只存在於瀏覽器
2、不在瀏覽器發請求是不會存在跨域問題的
3、http請求分為兩大類: 普通http請求(如百度請求)和ajax請求(跨域是出現在ajax請求)
2、在什么地方
瀏覽器會跨域 服務器不會
3、什么條件會跨域
同源(協議 ip 端口一致)不跨域
不同源就跨域(三個中間有一個不一樣就跨域)
http://localhost:8080/ ------- 》 github (有得是后台解決了允許跨域,前端如何解決跨域)
4、解決跨域:前端可以解決、后端解決。一般后端解決比前端解決容易
1.如果端口9000的服務向端口8000的端口發送請求,這一定跨域了,此時我們需要在在webpack配置文件中devserer中配置Proxy代理
async searchAjax(q) {
try {
const result = await axios({
url: "http://localhost:9000/api/users/info",
method: "get"
});
console.log(result.data);
} catch (error) {
console.log(error);
}
在webpack配置文件中devserer中配置Proxy代理
//3. 增加 devServer 配置
devServer: {
open: true, // 自動打開瀏覽器
compress: true, // 啟動gzip壓縮
port: 9000, // 端口號
quiet:true,
// proxy:{
// // 請求路徑 http://localhost:9000/api/users/info
// //api會把http://localhost:9000覆蓋掉
// // 代理轉發路徑 http://localhost:8000/api/users/info
// // "/api":{ // // target :"http://localhost:8000", //目標路徑 // // pathRewrite: {"^/api" : ""}, //代理會把身份標識去掉替換成空竄 // // changeOrigin:true // // },
// }
},
配置代理服務器的原理圖
二, vuex的核心
1、狀態管理是什么:
Vuex 是一個專為 Vue.js 應用程序開發的狀態管理模式,是一個插件。
它采用集中式存儲管理應用的所有組件的狀態(數據),並以相應的規則保證狀態以一種可預測的方式發生變化。
我們也可以認為它也是一種組件間通信的方式,並且適用於任意組件
2、理解:對vue應用中多個組件的共享狀態進行集中式的管理(讀/寫)
3、為什么要有這個(問題):
1)多個視圖依賴於同一狀態
2)來自不同視圖的行為需要變更同一狀態
3)以前的解決辦法
a.將數據以及操作數據的行為都定義在父組件
b.將數據以及操作數據的行為傳遞給需要的各個子組件(有可能需要多級傳遞)
4)vuex就是用來解決這個問題的
4、什么時候用:
Vuex 可以幫助我們管理共享狀態,並附帶了更多的概念和框架。這需要對短期和長期效益進行權衡。
也就是說應用簡單(組件比較少)就不需要使用(但是可以),如果應用復雜,使用就會帶來很大的便捷
5、Vuex核心:把所有的共享狀態數據拿出來放在Vuex中進行集中式管理
1、安裝vuex
2、創建單獨的模塊使用vuex 它是一個插件,按照插件使用方式
3、書寫四個核心對象
4、暴露模塊
5、在Vue配置項當中注冊vuex對象,store
6、在核心對象寫代碼
優化:
1、如果用戶再操作的時候就是很簡單的數據更改,那么可以不用分發給actions,直接提交給mutations去更改
2、頁面上如果數據不想寫的太長,可以利用getters,去計算出來,然后在組件computed當中獲取計算的這個數據
3、mapActions等
Vuex4個核心概念
state 代表初始狀態數據 是一個包含n個屬性(不是方法)的對象
getters 代表計算屬性數據 是一個包含n個計算屬性的方法的對象
actions 代表用戶行為數據 是一個包含n個用戶行為回調方法的對象,(用來映射組件用戶的行為回調函數)
mutations 代表直接修改數據的數據 是一個包含n個直接修改狀態數據方法的對象 (用來讓action的行為調用)
注意:只能通過mutations的方法去直接修改,也就是說要想寫state數據必須通過mutations
actions里面是用戶操作的行為回調函數,它的內部可以寫異步和判斷
mutations里面是直接修改數據的函數數據,它的內部不可以寫異步和判斷
1.安裝vuex, npm install vuex --save
2.新建文件夾vuex,文件store.js,
import Vue from 'vue'
import Vuex from 'vuex'
// 申明插件
Vue.use(Vuex)
3.在main.js引入import store from '@/vuex/store', 注冊store
const vm = new Vue({
el:'#root',
render: h => h(App),
store //如果我們聲明使用(注冊)store(vuex),那么每個組件對象都可以通過this.$store拿到我們的store對象
})
例子
1.入口文件main.js
import Vue from 'vue'
import App from '@/App'
import store from '@/vuex/store'
Vue.config.productionTip = false
const vm = new Vue({
el:'#root',
render: h => h(App),
store //如果我們聲明使用(注冊)store(vuex),那么每個組件對象都可以通過this.$store拿到我們的store對象
})
2.app組件
<template> <div> <button @click="increment">+</button> <button @click="decrement">-</button> <button @click="incrementIfOdd">如果是奇數加{{count}}</button> <button @click="incrementAsync">異步加{{count}}</button> </div> </template> <script> // 從store中映射action和state,解構方式,供組件使用 import {mapActions,mapState} from 'vuex' export default { name: 'App' //數據定義到vuex(store)里面 // methods:mapActions(['increment','decrement','incrementIfOdd','incrementAsync']) methods:{ //最原始的寫法 // increment(){ // //this.$store.dispatch分發觸發 store對象內部actions內部對應的方法 // this.$store.dispatch('increment') // }, // decrement(){ // this.$store.dispatch('decrement') // }, // incrementIfOdd(){ // this.$store.dispatch('incrementIfOdd') // }, // incrementAsync(){ // this.$store.dispatch('incrementAsync') // } // 使用mapActions簡化methods的寫法 //1、如果methods方法名稱和store對象actions內部的方法名稱一致,可以使用下面這樣的寫法 // ...mapActions(['increment','decrement','incrementIfOdd','incrementAsync']) //2、如果methods方法的名稱和store對象actions內部的方法名稱不一致,那么就不能使用數組這樣的寫法 ...mapActions(['decrement','incrementIfOdd','incrementAsync']), ...mapActions({'increment':'iincrement'}) }, computed:{ // count(){ // return this.$store.state.count // } ...mapState(['count']) } //之前的,數據是定義在組件內的 // data(){ // return { // count:0 // } // }, // methods:{ // increment(){ // this.count++ // }, // decrement(){ // this.count-- // }, // incrementIfOdd(){ // if(this.count % 2 === 1){ // this.count++ // } // }, // incrementAsync(){ // setTimeout(() => { // this.count++ // }, 1000); // } // } } </script> <style scoped> </style>
store.js
import Vue from 'vue' import Vuex from 'vuex' // 申明插件 Vue.use(Vuex)
const state = {
//是專門用來存(狀態)數據的地方,它是一個包含多個屬性和屬性值的對象
count:0
}
const mutations = {
//專門用來更新數據的各種方法組成的對象
//這些個方法,必須是直接修改數據的方法, 不能在這些方法內部存在 判斷 循環 異步
INCREMENT(state){
state.count++
},
DECREMENT(state){
state.count--
}
}
const actions = {
//專門用來和組件行為(用戶行為)進行對接的各種方法組成的對象 //還有一個作用,用來對接成功后,告知相應的mutations中的對應方法去修改數據
// context有commit和state屬性
// increment(context){
// //接到用戶的操作請求(用戶分發)之后,提交給相關的修改數據的函數去修改
// //在這里可以去寫 if for 異步
// context.commit('INCREMENT')
// }
//解構方式
iincrement({commit}){
//接到用戶的操作請求(用戶分發)之后,提交給相關的修改數據的函數去修改
//在這里可以去寫 if for 異步
commit('INCREMENT')
},
decrement({commit}){
//接到用戶的操作請求(用戶分發)之后,提交給相關的修改數據的函數去修改
//在這里可以去寫 if for 異步
commit('DECREMENT')
},
incrementIfOdd({commit,state}){
//action內部的方法可以if for 異步 但是mutations里面的不行
if(state.count % 2 === 1){
commit('INCREMENT')
}
},
incrementAsync({commit}){
setTimeout(() => {
commit('INCREMENT')
}, 1000);
}
}
const getters = {
//一系列的方法,計算屬性get方法,根據我們state內的數據計算出來用戶要使用的數據
}
//暴露Store
export default new Vuex.Store({
state,
mutations,
getters,
actions
})
三,案例,在vuex中發送ajax請求,main組件獲取vuex的數據
App組件
<template> <div class="container"> <Header></Header> <Main></Main> </div> </template> <script> import Header from '@/components/Header' import Main from '@/components/Main' export default { name: '', components:{ Header, Main } } </script> <style scoped> </style>
header組件
<template> <section class="jumbotron"> <h3 class="jumbotron-heading">Search Github Users</h3> <div> <input type="text" placeholder="enter the name you search" v-model="searchName" /> <button @click="search">Search</button> </div> </section> </template> <script> import {mapActions} from 'vuex' export default { name: "", data(){ return { searchName:'' } }, methods:{ // ...mapActions(['search']) search(){ //和store里面的某個actions方法去對應 //如果傳遞參數只有一個,可以直接傳 //如果傳遞多個,必須使用對象 this.$store.dispatch('search',this.searchName) } } }; </script> <style scoped> </style>
main組件
<template> <div> <h2 v-if="isFirst">歡迎光臨,請輸入關鍵字進行搜索</h2> <h2 v-else-if="isLoading">正在搜索中,請稍后</h2> <h2 v-else-if="errMsg">請求出錯:{{errMsg}}</h2> <div v-else class="row"> <div class="card" v-for="(user, index) in users" :key="user.userName"> <a :href="user.userUrl" target="_blank"> <img :src="user.userImg" style="width: 100px" /> </a> <p class="card-text">{{user.userName}}</p> </div> </div> </div> </template> <script> import axios from 'axios' // 從store中映射出state,供組件使用數據 import {mapState} from 'vuex' export default { name: "", // 接收state里的數據,mapState()返回的是一個對象,解包對象 computed:{ ...mapState(['isFirst','isLoading','errMsg','users']) } // data(){ // return { // isFirst:true, // isLoading:false, // errMsg:'', // users:[] // } // }, // mounted(){ // this.$bus.$on('searchAjax',this.searchAjax) // }, // methods:{ // searchAjax(q){ // //在發送ajax請求之前,讓頁面顯示正在請求中 // this.isFirst = false // this.isLoading = true // //就可以根據searchName去發送ajax請求 // this.$http({ // url:'https://api.github.com/search/us', // method:'get', // params:{ // q // } // }).then(response => { // let userList = response.data.items.map(item => { // return { // userName:item.login, // userUrl:item.url, // userImg:item.avatar_url // } // }) // this.users = userList // this.isLoading = false //請求成功拿到數據,顯示用戶信息 // }).catch(error => { // this.errMsg = error.statusText // this.isLoading = false //請求失敗拿到錯誤信息,顯示錯誤信息 // }) // } // } }; </script> <style scoped> .card { float: left; width: 33.333%; padding: 0.75rem; margin-bottom: 2rem; border: 1px solid #efefef; text-align: center; } .card > img { margin-bottom: 0.75rem; border-radius: 100px; } .card-text { font-size: 85%; } </style>
store.js
import Vue from 'vue'
import Vuex from 'vuex'
// 引入axios
import axios from 'axios'
// 申明插件
Vue.use(Vuex)
const state = {
isFirst:true,
isLoading:false,
errMsg:'',
users:[]
}
const mutations = {
REQUESTING(state){
state.isFirst = false
state.isLoading = true
},
REQUEST_SUCCESS(state,userList){
state.users = userList
state.isLoading = false //請求成功拿到數據,顯示用戶信息
},
REQUEST_FAILD(state,error){
state.errMsg = error.message
state.isLoading = false //請求失敗拿到錯誤信息,顯示錯誤信息
}
}
const actions = {
//{commit}解構
search(context,q){
//在發送ajax請求之前,讓頁面顯示正在請求中
context.commit('REQUESTING')
//就可以根據searchName去發送ajax請求
axios({
url:'https://api.github.com/search/users',
method:'get',
params:{
q
}
}).then(response => {
//返回一個新數組,數組中有個對象
let userList = response.data.items.map(item => {
return {
userName:item.login,
userUrl:item.url,
userImg:item.avatar_url
}
})
//請求成功后,提交給mutations,修改state的數據
context.commit('REQUEST_SUCCESS',userList)
}).catch(error => {
//發送請求失敗后,提交給mutations,修改state的數據,改變狀態
context.commit('REQUEST_FAILD',error)
})
}
}
const getters = {}
// 向外暴露store,給main.js
export default new Vuex.Store({
state,
mutations,
actions,
getters
})