vue-(3)PromiseVuex网络模块封装

Promise/Vuex/网络模块封装

1、Promise

ES6中一个非常重要和好用的特性就是Promise。

Promise是异步编程的一种解决方案。

避免当网络请求非常复杂时,就会出现回调问题。

1.1、Promise基本使用

new Promise((resolve,reject)=>{
setTimeout(function(){
resolve('xxx')
reject('Error Data')
},1000)
}).then(data=>{console.log(data);}).catch(error=>{console.log(error);})

new Promise很明显是创建一个Promise对象,小括号中((resolve, reject) => {})也很明显就是一个函数。成功:调用resolve(message),这个时候,我们后续的then会被回调。失败:调用reject(error),这个时候,我们后续的catch会被回调。

异步操作之后会有三种状态
pending:等待状态,比如正在进行网络请求,或者定时器没有到时间。
fulfill:满足状态,当我们主动回调了resolve时,就处于该状态,并且会回调.then()
reject:拒绝状态,当我们主动回调了reject时,就处于该状态,并且会回调.catch()

1.2、Promise链式调用

Promise.resovle():将数据包装成Promise对象,并且在内部回调resolve()函数
Promise.reject():将数据包装成Promise对象,并且在内部回调reject()函数

...
}).then(data=>{console.log(data);}).catch(error=>{console.log(error);})
.then(data=>{console.log(data);}).catch(error=>{console.log(error);})

2、Vuex

Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。

状态管理:把需要多个组件共享的变量全部存储在一个对象里面。然后,将这个对象放在顶层的Vue实例中,让其他组件可以使用。VueJS带给我们最大的便利是,所以要保证属性做到响应式,自己封装可能稍微麻烦一些,所以Vuex就是为了提供这样一个在多个组件间共享状态的插件。

2.1、Vuex的使用

创建一个文件夹store,并且在其中创建一个index.js文件
在index.js文件中写入如下代码

import Vuex from 'vuex'
import Vue  from  'vue'

Vue.use(Vuex)

const store = new Vuex.store({
state:{
	count:0
},
//Vuex中store数据改变的唯一方法就是mutation!
mutations:{
increment(state){state.count--}
}
})
export default store

然后挂载到Vue实例中,在main.js里面中

import  Vue from 'vue'
import App from './App'
import store from './store'

new Vue({
el:'#app',
store,
render:h=>h(App)
})

使用Vuex的count

<template中><button @click="increment">+1</buttton>

<script>
export default {
name:'App',
components:{},
computed:{
  count:function(){return this.$store.state.count}
},
methods:{
increment:function(){this.$store.commit('increment')}
}
}

小总结

1、提取出一个公共的store对象,用于保存在多个组件中共享的状态
2、将store对象放置在new Vue对象中,这样可以保证在所有的组件中都可以使用到
3、在其他组件中使用store对象中保存的状态即可
通过this.s t o r e . s t a t e . 属 性 的 方 式 来 访 问 状 态 通 过 t h i s . store.state.属性的方式来访问状态 通过this.store.state.访this.store.commit(‘mutation中方法’)来修改状态
注意事项:
1、我们通过提交mutation的方式,而非直接改变store.state.count。
2、这是因为Vuex可以更明确的追踪状态的变化,所以不要直接改变store.state.count的值。

2.2、Vuex核心概念

State、Getters、Mutation、Action、Module

2.2.1、State

单一状态树。实际开发中,如果你的状态信息是保存到多个Store对象中的,那么之后的管理和维护等等都会变得特别困难。所以Vuex也使用了单一状态树来管理应用层级的全部状态。单一状态树能够让我们最直接的方式找到某个状态的片段,而且在之后的维护和调试过程中,也可以非常方便的管理和维护。

2.2.2、Getters

场景:需要从store中获取一些state变异后的状态

getters:{
xxx:state=>{return state.students.filter(s=>s.age<-10).length}
}

Getters作为参数和传递参数

getters默认是不能传递参数的, 如果希望传递参数, 那么只能让getters本身返回另一个函数。

2.2.3、Mutation

Vuex的store状态的更新唯一方式:提交Mutation
Mutation主要包括两部分:
字符串的事件类型(type)
一个回调函数(handler),该回调函数的第一个参数就是state。
mutation的定义方式:

mutation:{incre(state){state.count++}}

通过mutation更新

incre:function(){this.$store.commit('incre')}

<Mutation传递参数>

通过mutation更新数据的时候携带一些额外的参数,参数被称为是mutation的载荷(Payload)

decrement(state,n){state.count -=n}

decrement:function(){this.$store.commint('decrement',2)}

如果参数是多个, 我们通常会以对象的形式传递,也就是payload是一个对象。然后再从对象中取出相关的信息。

decrement2(state,payload){state.count =payload.count}

decrement2:function(){this.$store.commint('decrement2',{count:0})}

<Mutation提交风格>

上面的通过commit进行提交是一种普通的方式
Vue还提供了另外一种风格, 它是一个包含type属性的对象

this.$store.commit({
type:'changeCount',
count:100
})

Mutation中的处理方式是将整个commit的对象作为payload使用, 所以代码没有改变

changeCount(state,payload){state.count =payload.count}

<Mutation响应规则>

Vuex的store中的state是响应式的, 当state中的数据发生改变时, Vue组件会自动更新。

(1)提前在store中初始化好所需的属性.
(2)当给state中的对象添加新属性时, 使用下面的方式:
方式一: 使用Vue.set(obj, ‘newProp’, 123)
方式二: 用新对象给旧对象重新赋值

mytations:{
updateInfo(state,payload){
//方法一
Vue.set(state.info,'height',payload.height)
//方法二
state.info={...state.info,'height':payload.geight}
}
}

<Mutation常量类型>

可以将这些常量放在一个单独的文件中, 方便管理。

mutations:{
[types.UPDATE_INFO](state,payload){
state.info={...state.info,'height':payload.height}
}
}

然后在vue文件中直接引用。

<Mutation同步函数>

通常情况下, Vuex要求我们Mutation中的方法必须是同步方法。

(1)主要的原因是当我们使用devtools时, 可以devtools可以帮助我们捕捉mutation的快照。
(2)但是如果是异步操作, 那么devtools将不能很好的追踪这个操作什么时候会被完成。

通常情况下, 不要再mutation中进行异步的操作

2.2.4、Action

比如网络请求, 必然是异步的。这个时候Action类似于Mutation, 但是是用来代替Mutation进行异步操作的。

context:通过context去进行commit相关的操作, 也可以获取context.state等。但是注意, 这里它们并不是同一个对象。

const store = new Vuex.Store({
state:{count:0},
mutations:{inc(state){state.count--}},
actions:{inc(context){context.commit('inc')}
})

<Action的分发>

在Vue组件中, 如果我们调用action中的方法, 那么就需要使用dispatch

methods:{
inc(){this.$store.dispatch('inc')}
}

<Action返回的Promise>

ES6语法中Promise经常用于异步操作。在Action中, 我们可以将异步操作放在一个Promise中, 并且在成功或者失败后, 调用对应的resolve或reject。

actions:{
inc(context){
  retrun new Promise((resolve)=>
  setTimeout((=>{
  context.commit('inc')
  resolve()
  },1000))
  )}}

调用

methods:{
inc(){
this.$store.dispatch('inc').then(res=>{
console.log('完成了更新');
})
}
}

2.2.5、Module

当应用变得非常复杂时,store对象就有可能变得相当复杂。所以我们将store分割成模块(Module), 而每个模块拥有自己的state、mutations、actions、getters等。

const moduleA={...}
const store = new Vuex.store({
modules:{a:moduleA}
})
store.state.a  //-->moduleA的状态

<modele中写Actions与getters>

const moduleA={
actions:{...}
getters:{...}
}

2.3、项目结构

api:抽出API请求

store/index.js:组装模块并导出store的地方

store/actions.js:根级别的action

store/mutations.js:根级别的mutation

store/modules:写自己项目的模块

3、网络模块封装

​ 常见的网络请求模块JSONP、axios

3.1、模块的选择

<1>不用Ajax
传统的Ajax是基于XMLHttpRequest(XHR),不使用的原因(1)配置和调用方式等非常混乱。(2)编码起来看起来繁琐,真实开发用的少,而是jQuery-Ajax。
<2>不用jQuery-Ajax
在Vue的整个开发中都是不需要使用jQuery了。如果用就相对于特意去使用了。
<3>不用Vue-resource(官方在Vue1.x的时候推荐)
因为Vue2.0之后,去掉了且不会再更新,不利于以后的维护。
<4>使用axios

3.1.1、jsonp封装

使用JSONP最主要的原因往往是为了解决跨域访问的问题。
JSONP的核心在于通过

3.1.2、axios

功能特点:在浏览器中发送 XMLHttpRequests 请求、在 node.js 中发送 http请求、支持 Promise API、拦截请求和响应、转换请求和响应数据等等

支持多种请求方式

axios(config)、axios.request(config)、axios.get(url[, config])、axios.delete(url[, config])、axios.head(url[, config])、axios.post(url[, data[, config]])、axios.put(url[, data[, config]])、axios.patch(url[, data[, config]])

<发送get请求>

import axios from 'axios'
export default{
name:'app',
created(){
//1、没有请求参数
axios.get('http://xxx').then(res=>{xxx}).catch(err=>{xxx})
}
//2、有请求参数
axios.get('http://xxx',params:{type:'sell',age:1}).then(res=>{xxx}).catch(err=>{xxx})
}
}

<发送并发请求>

有时候可能需求同时发送两个请求,使用axios.all, 可以放入多个请求的数组。axios.all([]) 返回的结果是一个数组,使用axios.spread 可将数组 [res1,res2] 展开为 res1, res2。

import axios from 'axios'
export default{
name:'app',
created(){
//2、发送并发请求
axios.all([axios.get('http://xxx'),axios.get('http://xxx'),{params:{type:'sell',age:1}}]).then(axios.spread((res1,res2)=>{
console.log(res1);
console.log(res2);
}))
}
}

<全局配置>

抽取一些公共固定的参数,如:

axios.defaults.baseURL = ‘IP’
axios.defaults.headers.post[‘Content-Type’] = ‘application/x-www-form-urlencoded’;

<常见的配置选项>

请求地址
url: ‘/user’,
请求类型
method: ‘get’,
请根路径
baseURL: ‘http://www.xx.com/api’,
请求前的数据处理
transformRequest:[function(data){}],
请求后的数据处理
transformResponse: [function(data){}],
自定义的请求头
headers:{‘x-Requested-With’:‘XMLHttpRequest’},
URL查询对象
params:{ id: 12 },
查询对象序列化函数
paramsSerializer: function(params){ }
request body
data: { key: ‘aa’},
超时设置s
timeout: 1000,
跨域是否带Token
withCredentials: false,
自定义请求处理
adapter: function(resolve, reject, config){},
身份验证信息
auth: { uname: ‘’, pwd: ‘12’},
响应的数据格式 json / blob /document /arraybuffer / text / stream
responseType: ‘json’,

3.1.3、实例

//创建新的实例
const axiosTns=axios.create({
baseURL:'xxx',
timeout:5000,
headers:{'Content-Type':'app;ication/x-www-from-x'}
})
//发送网络请求
axiosIns({
url:'/xx',
method:'get'
}).then(res=>{
console.log(xxx);
}).catch(err=>{xxx})

axios.js中封装

将实例和发送网络请求写一起

import originAxios from 'axios'
export default function axios(option){
return new Promise((resolve,reject)=>{
//创建实例与传入对象进行网络请求
})
}

3.2、拦截器

//配置请求和响应拦截
instance.interceptors.request.use(config=>{
console.log('来到了request拦截成功中')
return config
},err=>{console.log('来到了request拦截失败中');
return config})

instance.interceptors.response.use(response=>{
console.log('来到了response拦截成功中')
return response.data
},err=>{console.log('来到了response拦截失败中');
return err})

1、当发送网络请求时,添加动画组件
2、判断用户是否有token
3、对参数进行序列化

响应里面主要是对数据的过滤,再根据失败的不同状态跳不同页面。


版权声明:本文为qq_41429551原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。