vuex、axios
1 Vuex
针对Vue.js应用程序开发的状态管理模式,说白了就是:组件之间有些状态(简单理解为变量变量)希望互相共享,如果按照原来的父子组件传递,那就很麻烦,于是状态管理工具就应运而生。
Vuex就是组件共享数据的管家,放进去的状态是响应式的。
1.1 简单使用
安装vuex后会出来一个store文件夹,里面的index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
//保存状态
state: {
counter:1000
},
mutations: {
},
actions: {
},
modules: {
}
})
如果我们想使用state里的状态,在vue文件的template中
<template>
<div>
<h2>{{$store.state.counter}}</h2>
</div>
</template>
如果我们想改state,可以这样
<div>
<h2>{{$store.state.counter}}</h2>
<button @click="$store.state.counter++">+</button>
<button @click="$store.state.counter--">-</button>
</div>
但是vue官方不推荐这样直接改,因为这样修改会绕过vue的官方浏览器插件devtools,无法在开发中对vuex的状态进行监听。那么我们要怎么做呢?
首先我们修改vuex的index.js
//保存状态
state: {
counter:1000
},
mutations: {
increment(state){
state.counter++
},
decrement(state){
state.counter--
},
},
actions: {
},
modules: {
}
在mutations中注册相关方法(如果是异步网络请求需要先在actions中进行,再调用mutation中的方法修改)
然后再vue文件中通过commit来使用方法
<template>
<div>
<h2>{{$store.state.counter}}</h2>
<button @click="increment">+</button>
<button @click="decrement">-</button>
</div>
</template>
<script>
export default {
name: "HelloVUe",
methods:{
increment(){
return this.$store.commit('increment')
},
decrement(){
return this.$store.commit('decrement')
},
}
}
</script>
然后在浏览器就可以通过devtools来观察state的变化,可以看到每一步操作后state的变化。
1.2 Vuex核心概念
1.2.1 state单一状态树
单一状态树就是单一数据源,vue推荐把多个组件涉及到的状态管理为单一数据源。
1.2.2 getters
类似于计算属性
index.js中
getters:{
powerCounter(state){
return state.counter*state.counter
}
}
template:
<h2>getters使用</h2>
<h3>{{$store.getters.powerCounter}}</h3>
getters下的函数,第一个参数为state第二个为getters,所以我们可以在getters中利用其他getters
getters:{
powerCounter(state,getters){
return state.counter*state.counter
}
//平方之后+1
powerCounterPlus1(state,getters){
return powerCounter+1
}
}
如果我们希望用户使用getters时候可以传入一些参数要怎么做呢?利用回调函数传入参数
getters:{
//返回counter*自定义参数para
powerCounter(state){
return function(para){
return state.counter*para
}
}
}
1.2.3 mutation
mutation中可以传递额外的参数(可以是对象):
mutations:{
powerCounter(state,n){
return state.counter*n
}
}
除了commit方法提交,vue还提供了对象提交风格。以对象提交后,mutations中以对象接收输入的参数
//vue methods对象方式提交
decrement(){
return this.$store.commit({
type:'decrement',
count:1,
aaa:2
})
}
//vuex index.js中
decrement(state,payload){
console.log(payload);
//type: "decrement", count: 1, aaa: 2
state.counter--
}
响应式规则:vue中的响应式不是万能的,如果你在已经确定好属性的对象中添加新的属性,vue默认是不会执行响应式的。如何解决呢?
使用vue的set方法
Vue.set(state.obj,'key','value')
Vue.delete(state.obj,'key')//响应式删除属性
-
mutation常量
我们一般会把mutation绑定的函数名作为常量进行导入
创建mutation常量池:mutation-type.js
export const INCREMENT="increment"
在vuex中导入并使用
import * as mutationsType from './mutations-type' ... mutations: { [mutationsType.INCREMENT](state){ state.counter++ }, ...
vue文件中使用
import * as mutationsType from '../store/mutations-type' export default { name: "HelloVUe", methods:{ increment(){ return this.$store.commit(mutationsType.INCREMENT) }, ...
1.2.4 Actions
vuex要求我们不要在mutation中写异步操作,因为devtools还是无法追踪。我们需要使用Action,但是不能直接在Action中执行具体的操作,必须还是要通过mutations进行提交
- 首先在actions中定义异步操作(下例中aIncrement)
- 在异步操作中提交mutations的方法
- 在vue文件中通过dispatch(分发)实现异步操作
actions: {
//上下文对象
aIncrement(context){
//异步操作
setTimeout(()=>{
context.commit('increment')
},1000)
}
},
vue文件
methods:{
increment(){
this.$store.dispatch('aIncrement')
},
Actions可以联合Promise使用,index的Actions中
double(context) {
return new Promise((resolve, reject) => {
setTimeout(() => {
context.commit('double')
resolve("异步请求完毕")
}, 1000)
})
},
vue文件中
double() {
// this.$store.dispatch('double')执行Actions中的double方法,返回Promise对象
this.$store.dispatch('double').then(res => console.log(res))
}
1.2.5 Modules
vuex提供的单一状态树会导致状态较为臃肿,所以vuex提供了modules来管理这些vuex,每一个modules都可以包含自己的actions、mutations、getters、states
const ModuleA={
state:{
id:1,
name:'zhangsan'
},
mutations:{},
actions:{},
getters:{}
};
...
modules: {
a:ModuleA
}
})
使用,a这个module的state会放到$store的state中
<h2>modules使用</h2>
<h3>{{$store.state.a.name}}</h3>
模块中的getters有第三个属性rootState,这个属性可以访问store的state
getters:{
getter1(state,getters,rootState){
console.log(rootState.counter);
}
}
模块中的actions的commit只能调用自己模块中的东西
1.2.6 vuex目录结构
我们可以把vuex的getters mutations actions modules都抽取为单独的js,通过导入来管理
index.js就变成这样
import Vue from 'vue'
import Vuex from 'vuex'
import {mutations} from "./mutations"
import {actions} from "./actions";
import {getters} from "./getters";
import {ModuleA} from "./modules/moduleA";
Vue.use(Vuex)
const state = {
state: {
counter: 1000
},
}
export default new Vuex.Store({
state,
mutations,
actions,
getters,
modules: {
a: ModuleA
}
})
2 axios
2.1 基本使用
params会自动作为get请求中的参数进行拼接
axios({
url:'https://httpbin.org/get'
}).then(res=>{
console.log(res);
})
axios({
url:'https://httpbin.org/home/data',
params:{
type:'pop',
page:1
}
}).then(res=>{
console.log(res);
})
//2. 并发请求
axios.all([axios({
url: ""
}), axios({
url: ""
})]).then((res) => {
});
2.2 配置
axios.defaults.baseURL="https://httpbin.org";//默认地址路径
axios.defaults.timeout=5000;//超时时间
axios({
url: '/get'
...
但是开发里一般不用全局的,通过创建一个axios实例进行处理
const instance1 = axios.create({
baseURL: "https://httpbin.org",
timeout: 5000//超时时间
});
instance1({
url: ''
}).then(() => {
})
2.3 拦截器
通过设置请求拦截器和响应拦截器,对请求进行预处理或是对响应数据进行预处理
import axios from 'axios'
export function request(config) {
//1.创建axios实例
const instance=axios.create({
baseURL:'http://123.207.32.32:8000/api/v1',
timeout:1000000
});
//请求拦截
instance.interceptors.request.use((config)=>{
console.log(config);//config为网络请求的信息配置,拦截器就可以对请求做一些限定
return config;//这里必须返回,否则会被拦截掉
},(error)=>{
console.log(error)
})
//响应拦截 拦截成功和拦截失败
instance.interceptors.response.use((res)=>{
console.log(config);
return res.data;
},(error)=>{
console.log(error)
})
return instance(config)//Promise对象
}