Vuex 是一個專爲 Vue.js 應用程序開發的狀態管理模式。它採用集中式存儲管理應用的全部組件的狀態,並以相應的規則保證狀態以一種可預測的方式發生變化。Vuex 也集成到 Vue 的官方調試工具 devtools extension,提供了諸如零配置的 time-travel 調試、狀態快照導入導出等高級調試功能。php
狀態管理核心html
axios 是一個基於Promise 用於瀏覽器和 nodejs 的 HTTP 客戶端,它自己具備如下特徵:vue
axios並無install 方法,因此是不能使用vue.use()方法的。node
解決方法有不少種:webpack
使用 vue-axiosios
在主入口文件main.js中引用es6
1 import axios from 'axios' 2 import VueAxios from 'vue-axios' 3 Vue.use(VueAxios,axios);
axios 改寫爲 Vue 的原型屬性web
在主入口文件main.js中引用ajax
1 import axios from 'axios' 2 Vue.prototype.$axios= axios;
vue-resource是Vue.js的一款插件,它能夠經過XMLHttpRequest或JSONP發起請求並處理響應。vuex
vue-resource還提供了很是有用的inteceptor功能,使用inteceptor能夠在請求前和請求後附加一些行爲,好比使用inteceptor在ajax請求時顯示loading界面。
vue-resource的請求API是按照REST風格設計的,它提供了7種請求API:
get(url, [options])
head(url, [options])
delete(url, [options])
jsonp(url, [options])
post(url, [body], [options])
put(url, [body], [options])
patch(url, [body], [options])
vue-resource再也不繼續維護,推薦你們使用 axios 。
若是數據還有其餘組件複用,可放在vuex
若是須要跨多級組件傳遞數據,可放在vuex
須要持久化的數據(如登陸後用戶的信息),可放在vuex
跟當前業務組件強相關的數據,能夠放在組件內
第一步:在開發環境下安裝vuex
1 cnpm install vuex --save-dev
第二步:引用vuex,並實例化vuex狀態庫
創建一個store文件夾,創建一個index.js。在index.js中引入vue和vuex,日誌等
1 import Vue from 'vue' 2 import Vuex from 'vuex' 3 4 //每次修改state都會在控制檯打印log 5 import createLogger from 'vuex/dist/logger' 6 Vue.use(Vuex) 7 8 9 10 export default new Vuex.Store({ 11 actions:{}, 12 getters:{}, 13 state:{}, 14 mutations:{}, 15 })
第三步:store文件夾下建立state.js文件
這是咱們初始化數據的 ,也是以後咱們存數據的地方
1 const state = { 2 userInfo: {}, 3 MenuList: {} 4 } 5 export default state;
第四步:store文件夾下建立mutations.js文件
提交 mutations 是更改 vuex中 store 中狀態的 惟一方法
1 import * as types from './mutation-types' 2 import roleTokencate from "../caches/roleTokencate"; 3 4 const mutations = { 5 /* 6 * 登陸 7 */ 8 [types.SET_USERINFO](state, userInfo) { 9 console.log(types.SET_USERINFO, userInfo) 10 roleTokencate(userInfo); //存入緩存 11 12 state.userInfo = userInfo 13 }, 14 /* 15 * 獲取菜單列表 16 */ 17 [types.SET_MENULIST](state, data={}) { 18 state.MenuList = data 19 } 20 } 21 22 export default mutations
建立mutation-types.js文件,主要類型區分
1 export const SET_USERINFO = "userInfo";//登陸返回的用戶信息 2 export const SET_MENULIST = "MenuList";//返回的菜單列表
第五步:store文件夾下建立getters.js文件
vue 的計算屬性
1 export const userInfo = state => state.userInfo 2 export const MenuList = state => state.MenuList
第六步:store文件夾下建立actions.js文件
Action 提交的是 mutation,而不是直接變動狀態。 Action 能夠包含任意異步操做。
1 import * as types from './mutation-types' 2 import { getCurrUserMenu } from "./../services/auth"; 3 4 /** 5 * 登陸 獲取用戶信息 6 * @param context:與 store 實例具備相同方法和屬性的 context 對象 7 * @param Object:需管理的數據 8 */ 9 export function getUserInfoSync (context,Object) {//2.接受dispatch傳遞過來的方法和參數 10 //處理異步操做 11 setTimeout(()=>{ 12 //3.經過commit提交一個名爲getParam的mutation 13 //action 函數接受一個與 store 實例具備相同方法和屬性的 context 對象,所以你能夠調用 context.commit 提交一個 mutation 14 context.commit(types.SET_USERINFO,Object) 15 },1000) 16 }; 17 18 /** 19 * 獲取菜單列表 20 * @param context:與 store 實例具備相同方法和屬性的 context 對象 21 * @param Object:需管理的數據 22 */ 23 export function getMenuListSync (context,Object) { 24 context.commit(types.SET_MENULIST,Object) 25 }
第七步:store文件夾下建立modules文件夾
對應模塊js文件中,這裏我使用的home.js文件中編寫state、actions和mutations ,getters 等
vuex自帶模塊化方法,爲namespaced:true。經過對模塊進行命名空間設置,就能分模塊進行管理。
1 const state = { 2 initInfo: 'hello jackson' 3 } 4 const getters = { 5 initInfo(state, getters) { 6 return state.initInfo 7 } 8 } 9 const actions = { 10 getInfo({commit, state},data) { 11 console.log('getInfo==',data) 12 commit('updateInitInfo', 'getInfo') 13 } 14 } 15 const mutations = { 16 updateInitInfo(state, string) { 17 state.initInfo = string 18 console.log('home update', string) 19 } 20 } 21 22 export default { 23 namespaced: true, 24 state, 25 getters, 26 actions, 27 mutations 28 }
第八步:在開發環境下,開啓嚴格模式
引入日誌打印:
1 //每次修改state都會在控制檯打印log 2 import createLogger from 'vuex/dist/logger'
判斷是不是開發環境
1 const debug = process.env.NODE_ENV !== 'production'
添加到Vuex.Store庫中
1 export default new Vuex.Store({ 2 3 ... 4 5 strict: debug, // 當debug=true時開啓嚴格模式(性能有損耗) 6 plugins: debug ? [createLogger()] : [] 7 })
第九步:將上面建立的文件與方法,引入的第二步建立的store入口文件index.js中
1 import Vue from 'vue' 2 import Vuex from 'vuex' 3 import * as actions from './actions' 4 import * as getters from './getters' 5 import state from './state' 6 import mutations from './mutations' 7 import home from './modules/home' 8 9 //每次修改state都會在控制檯打印log 10 import createLogger from 'vuex/dist/logger' 11 Vue.use(Vuex) 12 13 const debug = process.env.NODE_ENV !== 'production' 14 15 export default new Vuex.Store({ 16 actions, 17 getters, 18 state, 19 mutations, 20 modules: { 21 home, 22 }, 23 strict: debug, // 當debug=true時開啓嚴格模式(性能有損耗) 24 plugins: debug ? [createLogger()] : [] 25 })
第十步:在項目的入口文件main.js中註冊使用
1 import 'amfe-flexible' 2 // The Vue build version to load with the `import` command 3 // (runtime-only or standalone) has been set in webpack.base.conf with an alias. 4 import Vue from 'vue' 5 // By default we import all the components. 6 // Only reserve the components on demand and remove the rest. 7 // Style is always required. 8 import VueResource from 'vue-resource' 9 10 import App from './App' 11 import router from '../router' 12 import store from '../store' 13 Vue.config.productionTip = false 14 Vue.use(VueResource) 15 /* eslint-disable no-new */ 16 new Vue({ 17 el: '#app', 18 router, 19 store, 20 template: '<App/>', 21 components: { App } 22 })
第十一步:在xxx.vue中使用
1,設置數據
(1),調用actions中的方法
1 this.$store.dispatch('getUserInfoSync',res.data.data[0])
(2),調用mutations中的方法
引入mapMutations
1 import { mapMutations } from "vuex";
使用
1 import { mapMutations } from "vuex"; 2 export default { 3 name: "Login", 4 data() { 5 return { 6 loginCode: undefined, 7 password: undefined, 8 isEye: true, 9 isChecked: true 10 }; 11 }, 12 mounted() { 13 14 }, 15 methods: { 16 17 // 登錄 18 loginAction() { 19 let loginData = { 20 loginCode: this.$data.loginCode, 21 password: this.$data.password 22 }; 23 if (this.$data.isChecked) { 24 loginRememberCate(loginData); 25 } 26 //不簡寫login 27 this.$http(login(loginData)) 28 //es6寫法 .then()部分 29 .then(res => { 30 console.log(res.data); 31 if (res.data.httpCode === 200) { 32 if (res.data.data && res.data.data.length > 0) { 33 this.setUserInfo(res.data.data[0]); 34 } 35 } 36 }) 37 .catch(err => { 38 39 console.log("錯誤信息==", err.data); 40 }); 41 }, 42 ...mapMutations({ 43 setUserInfo: "SET_USERINFO" 44 }) 45 } 46 };
2,獲取數據
引入mapGetters
1 import {mapGetters} from 'vuex'
使用
1 computed:{ 2 ...mapGetters([ 3 'userInfo','MenuList' 4 ]) 5 }, 6 mounted() { 7 console.log('this.userInfo==',this.userInfo); 8 console.log('this.MenuList==',this.MenuList); 9 },
第一步:安裝axios
1 cnpm install axios --save
第二步:引入axios並封裝
QS是axios庫中帶的,不須要咱們再npm安裝一個
1 import axios from 'axios' 2 import QueryString from 'qs'; 3 4 function checkHttpStatus(response) { 5 if (response.status >= 200 && response.status < 300) { 6 return response; 7 } 8 const error = new Error(response.statusText); 9 error.response = response; 10 error.code = response.status; 11 throw error; 12 } 13 14 function getResult(json) { 15 if (json.status === 200) { 16 let result = { result: json.data.data }; 17 return result; 18 } 19 } 20 /** 21 * 通用配置 22 * @param url:接口地址 23 * @param options:配置 24 * @param return{*} 25 */ 26 function request(url = '', options = {}, cache) { 27 // debugger 28 console.info('request ' + url); 29 let data; 30 let contentType; 31 if (typeof cache === 'function') { 32 data = cache(); 33 if (data) { 34 return Promise.resolve(data); 35 } 36 } 37 data = options.data; 38 delete options.data; 39 contentType = options.contentType; 40 delete options.contentType; 41 const opts = { 42 method: 'POST', 43 url, 4445 ...options 46 }; 47 opts.headers = { 48 ...opts.headers, 49 }; 50 if (opts.method === 'GET') { 51 url = url.split('?'); 52 url = url[0] + '?' + QueryString.stringify(url[1] ? { ...QueryString.parse(url[1]), ...data } : data); 53 opts.headers['content-type'] = contentType ? contentType : 'application/json'; // 54 } else { 55 opts.headers['content-type'] = contentType ? contentType : 'application/json'; // 56 opts.data= contentType === 'application/x-www-form-urlencoded' ? serialize(data) : JSON.stringify(data); 57 } 58 // 支持處理緩存 59 const handleCache = data => { 60 typeof cache === 'function' && cache(data.result); 61 return data; 62 }; 63 64 return axios(opts) 65 .then(checkHttpStatus) 66 .then(getResult) 67 .then(handleCache) 68 .catch(err => ({ err })); 69 } 70 export default request; 71
第三步:使用axios
1 import requestAxios from './requestAxios'; 2 import { POST, PUT } from '../utils/const'; 3 4 /* 5 ***獲取可訪問菜單*** 6 */ 7 export function getCurrUserMenu(data) { 8 return requestAxios('/api/v1/yingqi/user/getCurrUserMenu', { data, method: PUT }); 9 }
在store中actions中調用接口
1 import { getCurrUserMenu } from "./../services/auth"; 2 3 export function getMenuListAxiosSync (context,payload) { 4 getCurrUserMenu(payload.data) 5 .then(action => { 6 // alert('action中調用封裝後的axios成功'); 7 payload.getResult(action.result) 8 console.log('action中調用封裝後的axios成功',action.result) 9 context.commit(types.SET_MENULIST, action.result) 10 }) 11 }
第一步:安裝vue-resource
1 cnpm install vue-resource --save
第二步:在入口文件中引入使用
1 import VueResource from 'vue-resource' 2 Vue.use(VueResource)
封裝共同訪問參數
1 /** 2 * 通用配置 3 * @param url:接口地址 4 * @param options:配置 5 * @param return{*} 6 */ 7 export function request(url, options) { 8 // // post 傳參數 須要加 {emulateJSON:true} 9 // this.$http.post('in.php',{a:1,b:2},{emulateJSON:true}).then( (res) => { 10 // console.log(res.data) 11 // } ) 12 13 // // get傳參數 須要 {params: {你傳的值}} 14 // this.$http.get('getin.php',{params: {a:1,b:2}}).then( (res) => { 15 // console.log(res.data) 16 // }) 17 18 // // jsonp 傳參數 19 // this.$http.jsonp("https://sug.so.360.cn/suggest",{params:{word:'a'}}).then( (res)=>{ 20 // console.log(res.data.s) 21 // }) 22 let data; 23 let contentType; 24 data = options.data; 25 delete options.data; 26 contentType = options.contentType; 27 delete options.contentType; 28 const opts = { 29 method: 'POST', 30 url, 31 emulateJSON: true, 32 ...options 33 }; 34 opts.headers = { 35 ...opts.headers, 36 }; 37 opts.headers['content-type'] = contentType ? contentType : 'application/json'; // 38 opts.body = contentType === 'application/x-www-form-urlencoded' ? serialize(data) : JSON.stringify(data); 39 40 return opts; 41 } 42 export default request;
第三步:使用
1 import request from './request';//request 2 import { POST, PUT } from '../utils/const'; 3 /* 4 ***登錄*** 5 */ 6 export function login(data) { 7 return request('/api/v1/yingqi/user/login', { data, method: POST }); 8 }
在xxx.vue中調用接口
1 import { login } from "../../services/auth"; 2 ... 3 4 this.$http(login(loginData)) 5 //es6寫法 .then()部分 6 .then(res => { 7 console.log(res.data); 8 if (res.data.httpCode === 200) { 9 if (res.data.data && res.data.data.length > 0) { 10 console.log("res.data.data", res.data.data[0]); 11 } 12 } 13 }) 14 .catch(err => { 15 16 console.log("錯誤信息==", err.data); 17 }); 18 19 ...
第一步:建立axios實例
1 const service = axios.create({ 2 baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url 3 withCredentials: true, // send cookies when cross-domain requests 4 timeout: 50000 // request timeout 5 })
第二步:請求攔截器
1 service.interceptors.request.use( 2 config => { 3 // 發送請求以前作配置 通常配置token 4 //config.headers['X-Token'] = getToken() 5 return config 6 }, 7 error => { 8 // 請求異常 9 console.log(error) // for debug 10 return Promise.reject(error) 11 } 12 )
第三步:返回攔截器
1 service.interceptors.response.use( 2 /** 3 * 若是您想得到諸如頭信息或狀態信息 4 * Please return response => response 5 */ 6 7 response => { 8 const res = response.data 9 if (res.code !== 0) {//狀態碼錯誤/異常時處理 10 return Promise.reject(res.message || 'error') 11 } else {//請求成功返回 12 return res 13 } 14 }, 15 error => {//接口返回異常 16 console.log('err' + error) // for debug 17 return Promise.reject(error) 18 } 19 )
第四步:調用封裝
1 export function login(data) { 2 return request({ 3 url: '/api/v1/yingqi/user/login', 4 method: 'post', 5 data: { 6 loginCode: data.loginCode, 7 password: data.password 8 } 9 }) 10 }
第五步:在狀態管理裏調用
1 const actions = { 2 // user login 3 login({ commit }, userInfo) { 4 const { loginCode, password } = userInfo 5 return new Promise((resolve, reject) => { 6 login({ loginCode: loginCode.trim(), password: password }).then(response => { 7 const { data } = response 8 commit('SET_TOKEN', data.token) 9 resolve() 10 }).catch(error => { 11 reject(error) 12 }) 13 }) 14 }, 15 }
第六步:在頁面調用actions
1 handleLogin() { 2 // this.loginForm= {loginCode: 'loginCode', password: '123456'}, 3 this.$refs.loginForm.validate(valid => { 4 if (valid) { 5 this.loading = true 6 this.$store.dispatch('user/login', this.loginForm) 7 .then(() => { 8 //路由跳轉 9 this.loading = false 10 }) 11 .catch(() => { 12 this.loading = false 13 }) 14 } else { 15 console.log('error submit!!') 16 return false 17 } 18 }) 19 }
1,刷新後,在vuex中的數據會丟失
vuex 刷新 數據丟失問題
解決思路: localStorage 本地存儲
解決辦法:
mutations.js 裏面存數據,不用每一個組件都存一次
1 import * as types from './mutation-types' 2 import roleTokencate from "../caches/roleTokencate"; 3 import commonCache from "../caches/commonCache"; 4 5 const mutations = { 6 /* 7 * 登陸 8 */ 9 [types.SET_USERINFO](state, userInfo) { 10 console.log(types.SET_USERINFO, userInfo) 11 roleTokencate(userInfo); //存入緩存 12 commonCache(types.SET_USERINFO,userInfo); //存入緩存 防止數據丟失 13 state.userInfo = userInfo 14 }, 15 } 16 17 export default mutations
在state.js 裏面 加入如下代碼 :
1 import commonCache from "../caches/commonCache"; 2 3 ... 4 5 for (var item in state) { 6 let getCacheData = commonCache(item);//從緩存中獲取數據 7 getCacheData ? (state[item] = typeof getCacheData ==='string'?JSON.parse(getCacheData):getCacheData) : false;//防止頁面刷新vuex中的數據丟失 8 }
2,axios請求https後臺接口時,老是走error
axios開發環境配置代理請求https後臺接口時,若是是ip地址,例如thinkjs後臺接口地址https:127.0.0.1:8080,就會老是走error,沒法正常獲取後臺接口的返回值;可是若是是域名的話,則無這種狀況。
解決思路:target默認狀況下,不接受運行在HTTPS上,且使用了無效證書的後端服務器。若是你想要接受, 則需設置
secure
爲false;
解決辦法:在配置代理proxyTable裏添加以下屬性
1 // 是否驗證SSL證書 2 secure: false,
完整的配置以下:
1 proxyTable: { 2 "/api": { 3 // 傳遞給http(s)請求的對象 4 target: "http://127.0.0.1:8880", 5 // 是否將主機頭的源更改成目標URL 6 changeOrigin: true, 7 // 是否代理websocket 8 ws: true, 9 // 是否驗證SSL證書 10 secure: false, 11 // 重寫set-cookie標頭的域,刪除域名 12 cookieDomainRewrite: '', 13 // 代理響應事件 14 //onProxyRes: onProxyRes, 15 // 重寫目標的url路徑 16 pathRewrite: { 17 '^/api' : '/api' 18 } 19 }
代理響應事件
1 /** 2 * 過濾cookie path,解決同域下不一樣path,cookie沒法訪問問題 3 * (實際上不一樣域的cookie也共享了) 4 * @param proxyRes 5 * @param req 6 * @param res 7 */ 8 function onProxyRes (proxyRes, req, res) { 9 let cookies = proxyRes.headers['set-cookie'] 10 // 目標路徑 11 let originalUrl = req.originalUrl 12 // 代理路徑名 13 let proxyName = originalUrl.split('/')[1] || '' 14 // 開發服url 15 let server = configDev.servers[proxyName] 16 // 後臺工程名 17 let projectName = server.substring(server.lastIndexOf('/') + 1) 18 // 修改cookie Path 19 if (cookies) { 20 let newCookie = cookies.map(function (cookie) { 21 if (cookie.indexOf(`Path=/${projectName}`) >= 0) { 22 cookie = cookie.replace(`Path=/${projectName}`, 'Path=/') 23 return cookie.replace(`Path=//`, 'Path=/') 24 } 25 return cookie 26 }) 27 // 修改cookie path 28 delete proxyRes.headers['set-cookie'] 29 proxyRes.headers['set-cookie'] = newCookie 30 } 31 }
1 secure: false, // 若是是https接口,須要配置這個參數
如需完整代碼,請先留言評論加關注