Error message here!

Hide Error message here!

忘记密码?

Error message here!

请输入正确邮箱

Hide Error message here!

密码丢失?请输入您的电子邮件地址。您将收到一个重设密码链接。

Error message here!

返回登录

Close

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

jackson影琪 2019-01-31 10:01:00 阅读数:396 评论数:0 点赞数:0 收藏数:0

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

一,介绍与需求

 1.1,介绍

1,状态管理(vuex)

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

状态管理核心

  1. state里面就是存放项目中需要多组件共享的状态
  2. mutations就是存放更改state里状态的方法
  3. getters就是从state中派生出状态,比如将state中的某个状态进行过滤然后获取新的状态。
  4. actions就是mutation的加强版,它可以通过commit mutations中的方法来改变状态,最重要的是它可以进行异步操作
  5. 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
跟当前业务组件强相关的数据,可以放在组件内

二,状态数据管理

vue项目搭建与部署

第一步:在开发环境下安装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 },

三,接口调用

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 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 }

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 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 ...

四常见问题

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 }

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

版权声明
本文为[jackson影琪]所创,转载请带上原文链接,感谢
https://www.cnblogs.com/jackson-zhangjiang/p/10303364.html

编程之旅,人生之路,不止于编程,还有诗和远方。
阅代码原理,看框架知识,学企业实践;
赏诗词,读日记,踏人生之路,观世界之行;

支付宝红包,每日可领