Vue.js学习第十五天

Vuex中各个属性的使用

今天的学习围绕一张图片展开(图片引用自Vuex官方文档),当我们的项目比较大时,Vuex为我们在可以在组件外部管理状态提供了条件
图片引用自Vuex官方文档
一、 State
      【解释状态的意思,顾名思义,这里就是存放状态的地方,简单来说,就是存放你需要共享的某些变量的地方
      【使用】当我们在state中设置了相应的变量后,我们就可以来引用它们了,之前说过,当我们安装了Vuex后,会在全局生成一个store对象,我们可以使用,我们就可以使用这个store对象来访问我们的变量,如<h2>{{$store.state.counter}}</h2>,couter我已经在state中添加了它的值
      【相关知识State单一状态树(Single Source of Truth)又叫做单一数据源,也就是说Vuex中建议我们在Store中存放一个Store对象的实例,这个实例就是数据源,如果数据源特别多,就不容易进行后期的维护和管理,所以最好只有一个Store实例,这就叫做单一状态树
二、 Mutations
      【解释转变、改变的意思,和Vue实例中的methods属性差不多,主要存放的是处理数据的各个方法
      【使用】在Mutations中定义的各个函数都会有一个参数state,用来获取相应的数据,可以通过state调用state中存储的数据,进行相应转化,比如当我们在一个按钮中监听点击事件调用的那个函数时,函数中需要使用this.$store.commit(Mutations中的函数名);来调用Mutations中的函数进行处理,在commit中还可以同时提交一个对象交由Mutations处理,例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 第一种风格
addStu(){
const info = {
id:1005,
name:'lzx',
age:20
}
//payload
this.$store.commit('addStu',info);
// 第二种风格
jianCoun(num){
this.$store.commit({
type: 'resolveNum',
num,
age:18
})
},

这里我们传了一个info对象,这个info对象就被叫做payload,负载、载荷的意思,同时我们可以这么处理(students是state中的一个数组):

1
2
3
addStu(state,info){
state.students.push(info);
},

值得注意的是,在Vuex中同样有像Vue中数组的有些方法一样不是响应式的,因为Vuex中store状态的更新唯一方式是提交Mutations,比如state.info['address'] = 'LiShui'在info对象中添加属性address,值为‘LiShui’,我们应该这样Vue.set(state.info,'address','LiShui');还有一个delete state.info.age;也不是响应式的,应该修改为Vue.delete(state.info,'age');总之,我们必须遵守一些规则才能做到响应式:1. 提前在store中初始化好所需的属性;2.当给state中的对象添加新的属性时使用Vue.set或是用新对象给就对象重新赋值的方式进行

三、 Getters
      【解释获得、得到的意思,和Vue实例中的computed属性差不多,是对数据进行转化的地方
      【使用】同样,在getters中定义的各个函数都有一个state参数,除此之外还有一个geter参数,可以获得自己getter下的其它函数,例如:

1
2
3
4
5
6
moreAge(state){
return state.students.filter(s=>s.age>5);
},
numAge(state,get){
return get.moreAge.length;
},

调用也很简单

1
2
<h2>{{$store.getters.moreAge}}</h2>
<h2>{{$store.getters.numAge}}</h2>

同样的调用的时候也可以传入参数例如:
$store.getters.whatAge(30)
处理如下:

1
2
3
4
5
whatAge(state){
return age => {
return state.students.filter(s=>s.age>age);
}
}

这种用法注意一下,和灵活,返回可以是一个函数
四、 Actions
      【解释行动、行为的意思,在这里编写我们的异步代码,由最开始的那张图片我们可以知道,当你有一些异步请求时如果我们在 Mutations中处理,我们的Devtools没办好很好的跟踪这个操作什么时候会很好的完成,所以我们在Actions中编写我们的异步代码
      【使用】直接贴代码吧,一下是调用那端的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
changeStu(){
// 1. 这种方式第二个参数可以传函数,但是如果有其他参数就不好用了
// this.$store.dispatch('changeStu', () => {
// console.log('ok');
// })

// 2.既有函数又有其他参数 但是不够优雅
// this.$store.dispatch('changeStu',{
// message:'hello actions',
// succeed(){
// console.log('已完成');
// }
// })

//3. Promise
this.$store.dispatch('changeStu','hello actions').then(res => {
console.log('里面已经完成了');
console.log(res);
})
},

以下是处理那端代码,也就是actions中的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// context 上下文
changeStu(context,payload){
return new Promise((resolve,reject) => {
setTimeout(() => {
context.commit('changeStu');
console.log(payload);
resolve('11111')
}, 1000);
})
// setTimeout(()=>{

// console.log(payload);
// context.commit('changeStu');
// console.log(payload.message);
// payload.succeed();

// },1000)
}

五、 Modules
      【解释模块的意思,Vue使用的是单一状态数,那么也意味着很多状态都会交给Vuex来管理,当应用变得非常复杂时,store对象就有可能变得相当臃肿,为了解决这个问题,Vuex允许我们将store分割成模块,而每一个模块拥有自己的state mutations actions getters
      【使用】代码如下:
调用端的代码:

1
2
3
4
5
6
<h2>{{$store.state.a.name}}</h2>
<button @click="updataName">修改名字</button>
<h2>{{$store.getters.aUpdateName}}</h2>
<h2>{{$store.getters.bUpdateName}}</h2>
<h2>{{$store.getters.cUpdateName}}</h2>
<button @click="AsyncUpdataName">异步修改名字</button>

methods中的代码:

1
2
3
4
5
6
updataName(){
this.$store.commit('updateName','JYQ')
},
AsycUpdataName(){
this.$store.dispatch('AsycUpdateName');
}

module中的代码

1
2
3
 modules:{
a: moduleA,
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const moduleA = {
state:{
name: 'beanBag'
},
mutations:{
updateName(state,payload){
state.name = payload;
}
},
getters:{
aUpdateName(state){
return state.name + '1'
},
bUpdateName(state,getter){
return getter.aUpdateName + '2'
},
cUpdateName(state,getter,rootState){
return getter.bUpdateName + rootState.counter
}
},
actions:{
AsyncUpdateName(context){
setTimeout(() => {
context.commit('updateName','hqc');
}, 1000);
}
},
}

Vue.js学习第十六天

网络请求模块axios及项目相关

在开发项目的过程中,一定会使用到网络请求,使用一个合适的网络请求模块是很重要的,不论哪一种网络请求方式我们都需要自己封装,防止项目代码过于庞大不易管理,那么选择什么网络模块开发我们后边的项目呢?

参考一 、Ajax,ajax是基于XMLHttpRequest(XHR),但是配置后调用该方式非常混乱,真实开发很少用,所以不推荐
参考二、 jQuery封装好的Ajax,相对于传统的ajax来说,使用jQuery是更有优势的,但是这里产生一个问题,就是我们的项目是采用Vue来写的,在整个Vue模块中从未使用到jQuery,意味着为了一个网络请求要引用上万行的代码,这是不必要的,所以不推荐
参考三、官方在Vue1.x推出了Vue-resource,体积相对于jQuery来说比较小,同时是官方推出的,但是在Vue2.0版本以后,Vue作者将它从Vue中去除了,并且也说不会再更新,考虑到项目的安全性和以后的维护这里不推荐
参考四、Vue的作者在移除Vue-resource之后,推荐了一个第三方的框架,就是axios,它可以在浏览器中发送XMLHttpRequest请求,可以在node.js中发送http请求,这一点是jQuery做不到的,它支持Promise API,它支持拦截请求和相应,它支持转换请求和相应数据并且支持多种请求方式,综上,这里我们使用axiosOMG,你还在等什么,用它!用它!用它!

axios


为了理解方便,coderwhy老师将它理解为ajax i/o system我认为也是非常贴切的,下面让我们来使用一下吧
基本使用

  1. 安装axios框架
    npm install axios --save
  1. 导入

  2. 使用
    axios(config) //这里传入的config是一个对象,可以将配置信息传进去
    完整代码如下:

1
2
3
4
5
6
import axios from 'axios'
axios({
url: 'http://123.207.32.32:8000/home/multidata'
}).then(res => {
console.log(res);
})

4.注意点: axios返回的是一个Promise,这一点在后面的封装会用到,和ajax请求相同,默认是get请求方式,若要修改可以使用axios.get(config)或是在config中指明type即可

axios发送并发请求
上一次我们遇到并发请求的是Peomise.all的使用,同样,这里也有.all方法来实现并发请求,axios.all此方法返回的是一个数组,使用如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
axios.all([
axios({
url: 'http://123.207.32.32:8000/home/multidata'
}),
axios.get('http://123.207.32.32:8000/home/data',{
params:{
type:'sell',
page: 2
}
}
)]).then(results => {
console.log(results);
})

这里浏览器返回的是一个数组,如下图
在这里插入图片描述
我们可以在then中采用axios.spread方法直接返回两个对象,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
axios.all([
axios({
url: 'http://123.207.32.32:8000/home/multidata'
}),
axios.get('http://123.207.32.32:8000/home/data',{
params:{
type:'sell',
page: 2
}
}
)]).then(axios.spread( (res1,res2) => {
console.log(res1);
console.log(res2);
}))

这样打印出的是这样,两个对象的形式
在这里插入图片描述

axios全局配置
在以上使用的过程中,我们发现地址的前部分是相同,数据的请求方式也是相同的,这些相同的东西为了我们的简便以及后续的可维护性上考虑,我们可以将它抽离出来,即使用全局配置
如下:

1
2
3
//使用全局的axios和对应的配置在进行网络请求
axios.defaults.baseURL = 'http://123.207.32.32:8000'
axios.defaults.timeout = 5000

这里我们采用.default方法设置了一个基本的地址和浏览器的响应时间,在设置好了以后,就可以如下这么写我们的axios代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
axios.all([
axios({
url: '/home/multidata'
}),
axios.get('/home/data',{
params:{
type:'sell',
page: 2
}
}
)]).then(axios.spread( (res1,res2) => {
console.log(res1);
console.log(res2);
}))

注意点:这里我们还可以设置其它很多东西,例如请求方式,请求报文头中的一些信息,我们都可以将它指明,要注意的就是一旦声明的是params那么就要对应get请求,如果是request body中的相关参数,则要对应post请求

axios的实例和模块封装
在上面的全局配置中,我们又发现了一些问题,一旦我的网络请求很多,而每一个url有些相同,有些不同该怎么办,实际上在项目开发的过程中,如果是中大型的项目开发中,会将文件存放在多个服务器上,防止并发量过大造成的服务器的过载,在服务器端就会使用反向代理服务器(nginx部署),这在客户端就会拿到很多的url地址,那么怎么解决呢,axios为我们提供了一种解决办法,创建对应的axios实例,不再使用全局,使用如下:

1
2
3
4
5
6
7
8
9
10
const instance1 = axios.create({
baseURL: 'http://123.207.32.32:8000',
timeout: 5000
});

instance1({
url: '/home/multidata'
}).then(res => {
console.log(res)
})

最开始我们可能会感到多此一举,但是一旦项目中使用到的网络请求增加,并且有一些地址相同,另一些地址相同的情况下,就会感到方便很多了。

下面就可以进行模块封装了:
        一般情况下我们会先在src目录下新建一个文件夹,名称就叫network,代表用来处理网络相关的内容,文件夹下新建一个js文件文件名可以叫request.js,在这个页面中编写我们所有的网络请求的内容

  1. 基本使用(传入三个参数,对应的是三个函数)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import axios from 'axios'

export function request(config,success,failure){
// 1.创建axios实例
const instance = axios.create({
baseURL: 'http://123.207.32.32:8000',
timeout: 5000
})

instance(config).then(data=>{
// console.log(data);
success(data)
}).catch(err => {
// console.log(err);
failure(err)
})
}

调用时写的代码,按照指定的参数传入即可

1
2
3
4
5
6
7
8
9
10
11
request({
url:'/home/data',
params:{
type:'pop',
page:2
}
},success=>{
console.log(success)
},err => {
console.log(err)
});
  1. 传入一个参数,其实就是传入一个对象,对象中包含了上面的三个参数
1
2
3
4
5
6
7
8
9
10
11
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);
})
}

调用时写的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
request({
baseConfig:{
url:'/home/data',
params:{
type:'pop',
page:2
}
},
success(res){
console.log(res)
},
failure(err){
console.log(err)
}
})
  1. promise的使用(初期 为了理解这个过程)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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)
})
})

}

调用时写的代码

1
2
3
4
5
6
7
8
9
10
11
request({
url:'/home/data',
params:{
type: 'pop',
page: 1
}
}).then(res=>{
console.log(res);
}).catch(err => {
console.log(err)
})

这时我们发现,最开始的时候我们不是说过axios方法返回的不就是一个promise吗,所以大可不必在套一层,直接return回我们的instance即可,代码如下:

1
2
3
4
5
6
7
8
export function request(config){
// 1.创建axios实例
const instance = axios.create({
baseURL: 'http://123.207.32.32:8000',
timeout: 5000
})
return instance(config);
}

调用时的代码同上一个,这样就可以将我们处理从服务器端返回的数据和处理网络跳转的方法加以区分,更容易进行项目的维护

axios拦截器的使用
在axios中还有一个拦截器的特别我们没有介绍,拦截器可以分为以下2类,即拦截请求和拦截响应,这两类又对应着拦截成功和拦截失败的情况,下面先来看我们的拦截请求request
我们要使用到interceptors.request.use函数,具体看代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
export function request(config){
// 1.创建axios实例
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)
})

return instance(config);
}

这里我们拦截了instance的请求,我们可以对拦截的请求进行相关处理后继续传给服务器端进行响应,这里有几种用途: 1. 对不符合信息我们可以将它过滤之后再发出;2. 我们可以在他发出这个请求出先做一些加载动画,再将它返回给服务器; 3. 在一些需要登录才能访问的界面我们可以先拦截请求,在检查请求中是否含有token令牌,有的话继续,没有就跳转到登录页面,拦截失败的情况一般很少发生这里就不再赘述了;
另一个拦截响应的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
export function request(config){
// 1.创建axios实例
const instance = axios.create({
baseURL: 'http://123.207.32.32:8000',
timeout: 5000
})

instance.interceptors.response.use(res=>{
// console.log(res)
return res.data
},err=>{
console.log(err)
})

return instance(config);
}

这里我们使用的是interceptors.response.use,拦截响应,具体项目中我们可以做什么呢,就像是以上代码的,我们可以将服务器返回的数据我们进行处理以后再返回到客户端,这样就方便我们的处理,响应失败的情况比如说服务器找不到页面发出404请求等,我们就可以将他们的错误信息进行一些打印

项目相关


这里主要介绍一下怎么样进行GitHub上的托管

  1. 再GitHub上点+号,新建一个项目仓库
  2. 仓库创建好以后,复制项目的地址,输入命令,将GitHub上的文件克隆到本地,要注意克隆下来的项目名字不要和本地的名字相同
    git clone 复制的项目地址
    1. 将本地的文件拷贝到刚刚克隆的文件中,不要拷贝.git(里面已经有了)和node_modules(这个文件拷不拷贝都一样,配置文件中已经将它忽略)
    2. 在控制台中进入到文件目录
    3. 输入命令:git status查看状态 会看到文件都是红色
      1. git add. 添加一下文件
      2. git commit -m '一些说明信息'提交到本地
      3. git push推到仓库中即可将它们联系起来

还有一个命令可以让我们省略几步
git remote add origin 复制的项目地址
git push -u origin master
这样就可以直接将本地有的仓库和远程仓库联系起来