vue状态管理存取数据_Vue之状态管理(vuex)与接口调用

Vue之状态管理(vuex)与接口调用

一,介绍与需求

1.1,介绍

1,状态管理(vuex)

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。

状态管理核心

state里面就是存放项目中需要多组件共享的状态

mutations就是存放更改state里状态的方法

getters就是从state中派生出状态,比如将state中的某个状态进行过滤然后获取新的状态。

actions就是mutation的加强版,它可以通过commit mutations中的方法来改变状态,最重要的是它可以进行异步操作。

modules顾名思义,就是当用这个容器来装这些状态还是显得混乱的时候,我们就可以把容器分成几块,把状态和管理规则分类来装。这和我们创建js模块是一个目的,让代码结构更清晰。

2,axios

axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,它本身具有以下特征:

从浏览器中创建 XMLHttpRequest

从 node.js 发出 http 请求

支持 Promise API

拦截请求和响应

转换请求和响应数据

取消请求

自动转换JSON数据

客户端支持防止 CSRF/XSRF

axios并没有install 方法,所以是不能使用vue.use()方法的。

解决方法有很多种:

.结合 vue-axios使用

axios 改写为 Vue 的原型属性

使用 vue-axios

在主入口文件main.js中引用

1 import axios from 'axios'

2 import VueAxios from 'vue-axios'

3 Vue.use(VueAxios,axios);

axios 改写为 Vue 的原型属性

在主入口文件main.js中引用

1 import axios from 'axios'

2 Vue.prototype.$axios= axios;

3,vue-resource

vue-resource是Vue.js的一款插件,它可以通过XMLHttpRequest或JSONP发起请求并处理响应。

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 。

1.2,需求

如果数据还有其他组件复用,可放在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 newVuex.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 =userInfo13 },14 /*

15 * 获取菜单列表16 */

17 [types.SET_MENULIST](state, data={}) {18 state.MenuList =data19 }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.userInfo2 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 functiongetMenuListSync (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 returnstate.initInfo7 }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 =string18 console.log('home update', string)19 }20 }21

22 export default{23 namespaced: true,24 state,25 getters,26 actions,27 mutations28 }

第八步:在开发环境下,开启严格模式

引入日志打印:

1 //每次修改state都会在控制台打印log

2 import createLogger from 'vuex/dist/logger'

判断是否是开发环境

1 const debug = process.env.NODE_ENV !== 'production'

添加到Vuex.Store库中

1 export default newVuex.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 newVuex.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 newVue({17 el: '#app',18 router,19 store,20 template: '',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.password22 };23 if (this.$data.isChecked) {24 loginRememberCate(loginData);25 }26 //不简写login27 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 },

三,接口调用

3.1,axios访问接口

第一步:安装axios

1 cnpm install axios --save

第二步:引入axios并封装

QS是axios库中带的,不需要我们再npm安装一个

1 import axios from 'axios'2 import QueryString from 'qs';3

4 functioncheckHttpStatus(response) {5 if (response.status >= 200 && response.status < 300) {6 returnresponse;7 }8 const error =new Error(response.statusText);9 error.response =response;10 error.code =response.status;11 throwerror;12 }13

14 functiongetResult(json) {15 if (json.status === 200) {16 let result ={ result: json.data.data };17 returnresult;18 }19 }20 /**

21 *通用配置22 * @paramurl:接口地址23 * @paramoptions:配置24 * @param return{*}25 */

26 function request(url = '', options ={}, cache) {27 //debugger28 console.info('request ' +url);29 let data;30 let contentType;31 if (typeof cache === 'function') {32 data =cache();33 if(data) {34 returnPromise.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 ...options46 };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 returndata;62 };63

64 returnaxios(opts)65 .then(checkHttpStatus)66 .then(getResult)67 .then(handleCache)68 .catch(err =>({ err }));69 }70 export defaultrequest;71

第三步:使用axios

1 import requestAxios from './requestAxios';2 import { POST, PUT } from '../utils/const';3

4 /*

5 ***获取可访问菜单***

6 */

7 export functiongetCurrUserMenu(data) {8 return requestAxios('/api/v1/yingqi/user/getCurrUserMenu', { data, method: PUT });9 }

在store中actions中调用接口

1 import { getCurrUserMenu } from "./../services/auth";2

3 export functiongetMenuListAxiosSync (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 }

3.2,vue-resource访问接口

第一步:安装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 functionrequest(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 deleteoptions.data;26 contentType =options.contentType;27 deleteoptions.contentType;28 const opts ={29 method: 'POST',30 url,31 emulateJSON: true,32 ...options33 };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 returnopts;41 }42 export default request;

第三步:使用

1 import request from './request';//request

2 import { POST, PUT } from '../utils/const';3 /*

4 ***登陆***5 */

6 export functionlogin(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 ...

3.3,axios拦截器interceptors访问接口

第一步:创建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 returnconfig6 },7 error =>{8 //请求异常

9 console.log(error) //for debug

10 returnPromise.reject(error)11 }12 )

第三步:返回拦截器

1 service.interceptors.response.use(2 /**3 * 如果您想获得诸如头信息或状态信息4 * Please return response => response5 */

6

7 response =>{8 const res =response.data9 if (res.code !== 0) {//状态码错误/异常时处理

10 return Promise.reject(res.message || 'error')11 } else {//请求成功返回

12 returnres13 }14 },15 error => {//接口返回异常

16 console.log('err' + error) //for debug

17 returnPromise.reject(error)18 }19 )

第四步:调用封装

1 export functionlogin(data) {2 returnrequest({3 url: '/api/v1/yingqi/user/login',4 method: 'post',5 data: {6 loginCode: data.loginCode,7 password: data.password8 }9 })10 }

第五步:在状态管理里调用

1 const actions ={2 //user login

3 login({ commit }, userInfo) {4 const { loginCode, password } =userInfo5 return new Promise((resolve, reject) =>{6 login({ loginCode: loginCode.trim(), password: password }).then(response =>{7 const { data } =response8 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 =userInfo14 },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 proxyRes5 * @param req6 * @param res7 */

8 functiononProxyRes (proxyRes, req, res) {9 let cookies = proxyRes.headers['set-cookie']10 //目标路径

11 let originalUrl =req.originalUrl12 //代理路径名

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 returncookie26 })27 //修改cookie path

28 delete proxyRes.headers['set-cookie']29 proxyRes.headers['set-cookie'] =newCookie30 }31 }

1 secure: false, //如果是https接口,需要配置这个参数

如需完整代码,请先留言评论加关注

你可能感兴趣的:(vue状态管理存取数据)