文章目录
一. Promise01 Promise介绍和基本使用02 Promise三种状态03 Promise的链式调用04 Promise的all方法使用
二. Vuex01. Vuex概念和作用解析02. 单界面到多界面状态管理切换03. vue-devtools和mutations04. vue五个核心1. state单一状态树(Single Source of Truth 单一数据源)2. Getters3. mutations3. vuex-actions4. vuex-modules
三. axios01 axios框架的基本使用02 axios发送并发请求03 axios的配置信息相关04 axios的实例和模块封装05 axios拦截器的使用
一. Promise
01 Promise介绍和基本使用
Promise是异步编程的一种解决方案什么时候会处理异步事务? 一种很常见的场景就是网络请求,我们封装一个网络请求的函数,因为不能立即拿到结果,所以我们往往会传入另一个函数,在数据请求成功时,将数据通过传入的函数回调出去,如果只是简单的网络请求可以这样解决,但是当网络请求非常复杂时,就会出现回调地狱。
什么时候会用到Promise? 一般情况下是有异步操作时,使用Promise对这个异步操作进行封装
<script
>
new Promise((resolve
,reject
)=>{
setTimeout(()=>{
resolve('hello world')
reject('error msg')
},1000)
}).then((data
)=>{
console
.log(data
);
console
.log(data
);
console
.log(data
);
console
.log(data
);
}).catch((err
) => {
console
.log(err
);
})
</script
>
02 Promise三种状态
当开发中有异步操作的时候,可以给异步操作包装一个Promise
异步操作后会有三种状态
pending:等待状态,比如正在进行网络请求,或者定时器没有到时间。fulfill:满足状态,当我们主动回调了resolve时,就处于该状态,并且会回调.then()reject:决绝状态,当我们主动回调了reject时,就处于该状态,并且会回调.catch()
Promise的另外一种写法
<script
>
new Promise((resolve
,reject
)=>{
setTimeout(()=>{
reject('err msg')
},1000)
}).then(data
=>{
console
.log(data
);
},err
=>{
console
.log(err
);
})
</script
>
03 Promise的链式调用
*原始写法:
new Promise((resolve
,reject
)=>{
setTimeout(()=>{
resolve('aaa')
},1000)
}).then(res
=>{
console
.log(res
,'第一层的10行处理代码');
return new Promise((resolve
,reject
)=>{
reject('err')
})
}).then((res
)=>{
console
.log(res
,'第二层的10行处理代码');
return new Promise((resolve
)=>{
resolve(res
+'222')
})
}).then((res
)=>{
console
.log(res
,'第三层的10行处理代码');
}).catch(err
=> {
console
.log(err
);
})
简写 resolve
new Promise(resolve
=> resolve(结果
)) 简写
new Promise((resolve
,reject
)=>{
setTimeout(()=>{
resolve('aaa')
},1000)
}).then(res
=>{
console
.log(res
,'第一层的10行处理代码');
return Promise
.resolve(res
+'111')
}).then((res
)=>{
console
.log(res
,'第二层的10行处理代码');
return Promise
.resolve(res
+'222')
}).then((res
)=>{
console
.log(res
,'第三层的10行处理代码');
})
new Promise((resolve
,reject
)=>{
setTimeout(()=>{
resolve('aaa')
},1000)
}).then(res
=>{
console
.log(res
,'第一层的10行处理代码');
return res
+'111'
}).then((res
)=>{
console
.log(res
,'第二层的10行处理代码');
return res
+'222'
}).then((res
)=>{
console
.log(res
,'第三层的10行处理代码');
})
简写 reject
new Promise((resolve
,reject
)=>{
setTimeout(()=>{
resolve('aaa')
},1000)
}).then(res
=>{
console
.log(res
,'第一层的10行处理代码');
throw 'error msg'
}).then((res
)=>{
console
.log(res
,'第二层的10行处理代码');
return Promise
.resolve(res
+'222')
}).then((res
)=>{
console
.log(res
,'第三层的10行处理代码');
}).catch(err
=> {
console
.log(err
);
})
04 Promise的all方法使用
<script
>
Promise
.all([
new Promise((resolve
,reject
)=>{
setTimeout(()=>{
resolve({name
:'pao',age
:18})
},2000)
}),
new Promise((resolve
,reject
)=>{
setTimeout(()=>{
resolve({name
:'ko',age
:19})
},1000)
})
]).then(results
=> {
console
.log(results
);
})
</script
>
二. Vuex
01. Vuex概念和作用解析
Vuex是做什么的?
管理什么状态?(需要在多个界面共享的状态) 例如用户的登录状态,头像,名称或者商品的收藏、购物车里的物品等等。
02. 单界面到多界面状态管理切换
使用vuex之前需要先安装 在安装的时候我出现了一个小bug:http自签名失败 按照网上的教程可以解决:
使用vuex 创建文件夹store(仓库),新建index.js文件
import Vue
from 'vue'
import Vuex
from 'vuex'
Vue
.use(Vuex
)
const store
= new Vuex.Store({
state
:{
count
:1000
},
mutations
:{
},
actions
:{
},
getters
:{
},
modules
:{
}
})
export default store
import Vue
from 'vue'
import App
from './App'
import store
from './store'
Vue
.config
.productionTip
= false
new Vue({
el
: '#app',
store
,
render
: h
=> h(App
)
})
重新运行项目 我们不需要使用以前父子组件传值的方法,直接$store.state.count就可以获取在state中保存的值。
<template
>
<div
>
<h2
>{{$store
.state
.count
}}</h2
>
</div
>
</template
>
<script
>
export default {
name
:'HelloVuex',
}
</script
>
这里报错:因为我刚才在cmd终端安装的vuex,vscode可能没有反应过来,所以再安装一遍,安装出错可以试试:npm报错 按教程清一下缓存再安装:成功! 这时就可以npm run dev运行项目了。
03. vue-devtools和mutations
vue-devtools的安装:教程分享简单的使用案例:
创建文件夹store,创建index.js文件,我们在state中定义了一个共享的变量count,在mutations中定义了两个方法来控制count的增减。
import Vue
from 'vue'
import Vuex
from 'vuex'
Vue
.use(Vuex
)
const store
= new Vuex.Store({
state
:{
count
:1000
},
mutations
:{
increment(state
){
state
.count
++
},
decrement(state
){
state
.count
--
}
},
actions
:{
},
getters
:{
},
modules
:{
}
})
export default store
让所有vue组件都可以使用这个store对象,我们需要在main.js中导入store对象,并且放在new Vue中,这样在其他组件里就可以通过this.$store的方式获取这个store对象了。
import Vue
from 'vue'
import App
from './App'
import store
from './store'
Vue
.config
.productionTip
= false
new Vue({
el
: '#app',
store
,
render
: h
=> h(App
)
})
使用vuex的count * 通过this.$store.state属性的方法来访问状态 * 通过this.$store.commit(‘mutation中的方法’)来修改状态注意:我们是通过提交mutation的方式,而非直接改变this.$store.state.count,这样Vuex可以更加明确地追踪状态的改变,不要直接改变this.$store.state.count的值。
<template
>
<div id
="app">
<h2
>---------App内容
---------</h2
>
<h2
>{{$store
.state
.count
}}</h2
>
<button @click
="addition">+</button
>
<button @click
="substraction">-</button
>
<!-- <hello
-vuex
:count
="count"></hello
-vuex
> -->
<h2
>---------Hello Vuex内容
--------</h2
>
<hello
-vuex
/>
</div
>
</template
>
<script
>
import HelloVuex
from './components/HelloVuex'
export default {
name
: 'App',
data() {
return {
message
:'我是app组件',
}
},
components
: {
HelloVuex
},
methods
: {
addition(){
this.$store
.commit('increment')
},
substraction(){
this.$store
.commit('decrement')
}
},
}
</script
>
<style
>
</style
>
04. vue五个核心
1. state单一状态树(Single Source of Truth 单一数据源)
在开发中,如果状态信息是保存到多个store中的,那么之后的管理和维护等等都会变得比较困难,因此Vuex使用了单一状态树来管理应用层级的全部状态。单一状态树能够让我们以最直接的方式找到某个状态的片段,而且在之后的维护和调试过程中,也可以非常方便地管理和维护。
2. Getters
Getters的基本使用
const store
= new Vuex.Store({
state
:{
count
:1000,
students
:[
{id
:110,name
:'why',age
:18},
{id
:111,name
:'coco',age
:20},
{id
:112,name
:'lolo',age
:21},
{id
:113,name
:'hsh',age
:24},
]
},
mutations
:{...},
actions
:{},
getters
:{
powerCounter(state
){
return state
.count
* state
.count
},
more20stu(state
){
return state
.students
.filter(s
=> s
.age
>20)
}
},
modules
:{}
})
//App.vue --- 需要经过处理展示的数据都可以在state中的getters变化后获取
<h2>---------App内容,演示getters相关信息---------
</h2>
<h2>{{$store.getters.powerCounter}}
</h2>
<h2>{{$store.getters.more20stu}}
</h2>
不要直接在App.vue中定义计算属性来处理数据,因为这仅仅对App.vue一个页面有效。
// computed: {
// more20stu(){ //使用计算属性,拿到state中的students进行过滤,但是这样写,每一个界面都需要添加一样的计算属性代码
// return this.$store.state.students.filter(s=>{
// return s.age > 20 //可以直接省略{}和return
// })
// }
// },
getters作为参数和传递参数
getters
:{
...
more20stuLength(state
,getters
){
return getters
.more20stu
.length
},
moreAgeStu(state
){
return function(age
){
return state
.students
.filter(s
=> s
.age
>age
)
}
}
},
//App.vue
<h2>{{$store.getters.more20stuLength}}
</h2>
<h2>{{$store.getters.moreAgeStu(21)}}
</h2>
3. mutations
Vuex的store状态的更新唯一方式:提交MutationMutation主要包括两个部分: 字符串的事件类型(type) 一个回调函数(handler),该回调函数的第一个参数就是state
mutations传递参数 在通过mutation更新数据的时候,有时候希望携带一些额外的参数,这些参数被称为mutation的载荷(Payload)
mutations
:{
...
incrementCount(state
,count
){
state
.count
+= count
},
addStudent(state
,stu
){
state
.students
.push(stu
)
}
},
<button @click
="addCount(5)">+5</button
>
<button @click
="addCount(10)">+10</button
>
<button @click
="addStudent">添加学生
</button
>
...
methods
: {
...
addCount(count
){
this.$store
.commit('incrementCount',count
)
},
addStudent(){
const stu
= {id
:114,name
:'ami',age
:25}
this.$store
.commit('addStudent',stu
)
}
},
mutations提交风格
上面通过commit提交是一种普通的方式,Vue还提供了另外一种风格,它是一个包含type属性的对象。
addCount(count
){
this.$store
.commit({
type
:'incrementCount',
count
:count
})
},
incrementCount(state
,payload
){
state
.count
+= payload
.count
},
vuex响应式原理 state中定义的数据,它们的属性都会加入到响应式系统中,而响应式系统会监听属性的变化,当属性发生变化时,会通知所有界面中用到该属性的地方,让界面发生刷新。
我们必须遵守Vuex对应的规则:
提前在store中初始化好所需的属性当给state中的对象添加新属性时,使用下面的方式: 方式一:使用Vue.set(obj,‘newProp’,1) 方式二:用新对象给旧对象重新赋值
updateInfo(state
){
state
.info
.name
='codewhy'
Vue
.set(state
.info
,'address','洛杉矶')
Vue
.delete(state
.info
,'age')
}
mutations的类型常量 在mutation中,我们定义了很多事件类型(也就是其中的方法名称),当方法越来越多的时候,我们在多个文件之间来回切换,可能会写错方法的名字,所以我们最好把方法的名字抽取成常量。
我们可以把mutations中的方法类型全部在这里抽取成常量
export const INCREMENT = 'increment'
mutations
:{
[INCREMENT](state
){
state
.count
++
},
...
}
methods
: {
addition(){
this.$store
.commit(INCREMENT)
},
...
}
3. vuex-actions
通常情况下,Vuex要求我们Mutations中的方法必须是同步方法,主要原因是当我们使用devtools时,可以devtools可以帮助我们捕捉mutation的快照。但是如果是异步操作,那么devtools将不能很好地追踪这个操作什么时候会被完成。Action类似于Mutation,是用来代替mutation进行异步操作的。
虽然这样写看上去有点多余,但是却是必要的,这样我们的devtools就可以跟踪到修改了,并且在actions中也是可以传递参数或函数的。
mutations
:{
...
updateInfo(state
){
state
.info
.name
='codewhy'
}
},
actions
:{
aUpdateInfo(context
,payload
){
setTimeout(()=>{
context
.commit('updateInfo')
console
.log(payload
);
},1000)
--------------------------------------
setTimeout(()=>{
context
.commit('updateInfo')
payload()
},1000)
--------------------------------------
setTimeout(()=>{
context
.commit('updateInfo')
console
.log(payload
.message
)
payload
.success()
},1000)
}
},
updateInfo(){
this.$store
.dispatch('aUpdateInfo','我是传递来的参数')
--------------------------------------
this.$store
.dispatch('aUpdateInfo',()=>{
console
.log('里面已经完成了');
})
--------------------------------------
this.$store
.dispatch('aUpdateInfo',{
message
:'我是携带的信息',
success
:()=>{
console
.log('里面已经完成了');
}
})
}
更优雅的写法: actions中方法本身可以返回一个Promise,我们可以在另一个地方dispatch拿到这个Promise,在后面写then方法,就可以继续使用这个Promise了。
actions
:{
aUpdateInfo(context
,payload
){
return new Promise((resolve
,reject
)=>{
setTimeout(()=>{
context
.commit('updateInfo')
console
.log(payload
);
resolve('1111111')
},1000)
})
}
},
updateInfo(){
this.$store
.dispatch('aUpdateInfo','我是携带的信息').then(res
=>{
console
.log('里面已经完成了提交');
console
.log(res
);
})
}
4. vuex-modules
认识module(模块) Vue使用单一状态树,那么意味着很多状态都会交给Vuex来管理,当应用变得非常复杂时,store对象就有可能变得相当臃肿,为了解决这个问题,Vuex允许我们将store分割成模块,而每个模块拥有自己的state、mutations、actions、getters等
用法和之前是差不多的:
const moduleA
= {
state
:{
name
:'lisa'
},
mutations
:{
updatedName(state
,payload
) {
state
.name
= payload
},
},
getters
:{
fullname(state
){
return state
.name
+ '1111'
},
fullname2(state
,getters
){
return getters
.fullname
+ '2222'
},
fullname3(state
,getters
,rootState
){
return getters
.fullname2
+ rootState
.count
}
},
actions
:{
aUpdateName(context
){
setTimeout(()=>{
context
.commit('updatedName','wangwu')
},1000)
}
},
}
const store
= new Vuex.Store({
...
modules
:{
a
: moduleA
}
})
<h2
>---------App内容
,modules中的内容
---------</h2
>
<h2
>{{$store
.state
.a
.name
}}</h2
>
<button @click
="updateName">修改名字
</button
>
<h2
>{{$store
.getters
.fullname
}}</h2
>
<h2
>{{$store
.getters
.fullname2
}}</h2
>
<h2
>{{$store
.getters
.fullname3
}}</h2
>
<button @click
="asyncUpdateName">异步修改名字
</button
>
...
updateName(){
this.$store
.commit('updatedName','jenny')
},
asyncUpdateName(){
this.$store
.dispatch('aUpdateName')
}
vue-store文件夹的目录结构 除了state(没必要)之外,其他各个核心的代码都可以单独抽出来,方便管理。
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
= {
count
:1000,
students
:[
{id
:110,name
:'why',age
:18},
{id
:111,name
:'coco',age
:20},
{id
:112,name
:'lolo',age
:21},
{id
:113,name
:'hsh',age
:24},
],
info
:{
name
:'kobi',
age
:40,
height
:1.88
}
}
const store
= new Vuex.Store({
state
:state
,
mutations
:mutations
,
actions
:actions
,
getters
:getters
,
modules
:{
a
: moduleA
}
})
export default store
三. axios
01 axios框架的基本使用
1.安装axios框架 安装时出bug:代理有问题 找了一篇关于解决的博客:参考 还是不会安装,所以我尝试了另一个:cnpm 查了一下版本之后,居然就可以安装了,可能还是npm没反应过来吧。
使用axios
import Vue
from 'vue'
import App
from './App'
import axios
from 'axios'
Vue
.config
.productionTip
= false
new Vue({
el
: '#app',
render
: h
=> h(App
)
})
axios({
url
:'http://123.207.32.32:8000/home/multidata',
method
:'GET'
}).then(res
=> {
console
.log(res
);
})
axios({
url
:'http://123.207.32.32:8000/home/data',
params
:{
type
:'pop',
page
:1
}
}).then(res
=> {
console
.log(res
);
})
02 axios发送并发请求
axios
.all([
axios({
url
:'http://123.207.32.32:8000/home/multidata',
}),
axios({
url
:'http://123.207.32.32:8000/home/data',
params
:{
type
:'sell',
page
:5
}
})
]).then(axios
.spread((res1
,res2
) => {
console
.log(res1
);
console
.log(res2
);
}))
补充知识:
const obj
= {
name
:'kobi',
age
:30
}
const {name
,age
} = obj
const names
= ['why','are','you']
const [name1
,name2
,name3
] = names
03 axios的配置信息相关
axios
.defaults
.baseURL
= 'http://123.207.32.32:8000'
axios
.defaults
.timeout
= 5000
axios
.all([
axios({
url
:'/home/multidata',
}),
axios({
url
:'/home/data',
...
})
]).then(...)
04 axios的实例和模块封装
axios的实例 当项目变得复杂,接口的服务器不一定只有一个,这时我们使用全局配置的baseURL不满足需求,所以我们一般不会直接使用全局,而是创建一个实例,而且实例一般会有多个。
const instance1
= axios
.create({
baseURL
:'http://123.207.32.32:8000',
timeout
:5000
})
instance1({
url
:'/home/multidata'
}).then(res
=> {
console
.log(res
);
})
instance1({
url
:'/home/data',
params
:{
type
:'pop',
page
:1
}
}).then(res
=> {
console
.log(res
);
})
const instance2
= axios
.create({
baseURL
:'http://111.222.32.32:8000',
timeout
:10000,
headers
:{}
})
axios的模块封装 在使用第三方框架的时候,最好不要每个地方都引用,而是对它做一个封装,否则以后如果这个框架废弃或者出现问题时,更换框架会变得困难。
第一种封装:
import axios
from 'axios'
export function request(config
,success
,failure
){
const instance
= axios
.create({
baseURL
:'http://123.207.32.32:8000',
timeout
:5000
})
instance(config
)
.then(res
=> {
success(res
);
})
.catch(err
=> {
failure(err
);
})
}
import {request
} from './network/request';
request({
url
:'/home/multidata'
},res
=> {
console
.log(res
);
},err
=> {
console
.log(err
);
})
第二种封装:但是这种也不是最终方案
export function request(config
){
const instance
= axios
.create({
baseURL
:'http://123.207.32.32:8000',
timeout
:5000
})
instance(config
.baseConfig
)
.then(res
=> {
config
.success(res
);
})
.catch(err
=> {
config
.failure(err
);
})
}
request({
baseConfig
:{
},
success
:function(){
},
faliure
:function(){
}
})
第三种封装:使用Promise
export function request(config
){
return new Promise((resolve
,reject
) => {
const instance
= axios
.create({
baseURL
:'http://123.207.32.32:8000',
timeout
:5000
})
instance(config
)
.then(res
=> {
resolve(res
)
})
.catch(err
=> {
reject(err
)
})
})
}
-------------最终:简化后
-----------------------
export function request(config
){
const instance
= axios
.create({
baseURL
:'http://123.207.32.32:8000',
timeout
:5000
})
return instance(config
)
}
request({
url
:'/home/multidata'
}).then(res
=> {
console
.log(res
);
}).catch(err
=> {
console
.log(err
);
})
05 axios拦截器的使用
axios提供了拦截器,用于我们在发送每次请求或得到响应后,进行对应的处理。拦截请求或者响应之后还需要返回,否则信息被拦截,请求方获取不到。
export function request(config
){
const instance
= axios
.create({
baseURL
:'http://123.207.32.32:8000',
timeout
:5000
})
instance
.interceptors
.request
.use(config
=> {
console
.log(config
);
return config
;
},err
=> {
console
.log(err
);
});
instance
.interceptors
.response
.use(res
=> {
return res
.data
},err
=> {
console
.log(err
);
});
return instance(config
)
}