实现ajax的工具
ajax
有很多工具,比如浏览器自带的fetch
,或者vue
以前推荐的vue-resource
。现在vue
官方推荐用的是axios
,它可以实现跨平台的数据请求,比如说浏览器端可以发xhr
的请求,服务器上可以发送http
的请求。
这里用的是axios
。
引入axios
首先得安装axios,npm install axios --save
,安装完之后要记得去引入。去哪里引入呢?
首先分析一波,比如说首页,一般来说首页是由很多组件构成的,比如说这样:
每个组件都有自己的数据,难道每个组件在自己的组件内发送
ajax
请求吗?这样做是有问题的,首页一般由n个组件组成,每个组件发送一个
ajax
请求,那么首页至少有5个ajax
请求。那么网站的性能就非常低了。一般来说整个首页发一个
ajax
请求就行了。So去首页的那个组件去发送是最好的选择,这个大组件在获取ajax
数据后,可以把数据传给每个组件。
还记得组件的生命周期函数中有个mounted
吗?
一般ajax数据的获取是放在mounted
里面的,页面挂载成功就去请求数据。
如上图:
getHomeInfo: 这个函数是axios请求,具体的函数是要写在methods里的;
/api/index.json: 请求地址,这里是随意写的,根据实际地址来写;
axios返回的是一个promise对象,所以可以用then(this.getHomeInfoSucc)来接收返回结果。
getHomeInfoSucc:是成功时的执行函数。
此时浏览器是这样的:
浏览器报错
返回一个404,因为我们的请求地址是随便写的。
在没有后端的支持下,怎么实现数据的模拟呢?
mock数据
整个项目有一个static
目录,这个目录存放的是静态文件。
在
static
目录下新建一个mock
目录,然后新建一个json
文件,这里叫做index.json
,里面随便写点内容。为什么要放在
static
目录下呢?因为在整个工程里,只有
static
目录下的内容可以被外部访问到。比如在浏览器地址下输入这个:
json文件的内容显示了出来
可以看到
json
文件的内容。但是如果我们想访问
src
下的文件,输入这样的地址,会被重定向到首页。我又回到首页了
So我们可以把本地开发用到的模拟数据,都放在static
目录下。(!!!不是随便创个static
目录,就可以访问里面的内容,必须要配置,因为我这个项目是直接用的vue-cli
,已经自动配置好了)
【PS:这个mock
文件夹里放的都是本地的模拟数据,不想提交到线上的话,打开.gitignore
文件,添加一下文件夹名就可以了】
还没完,记得修改一下之前的axios
请求的地址,。
成功得到返回结果
等等,还没完。
现在出现了一个新的问题,因为目前用的都是本地模拟的数据,要是代码上线,请求地址肯定不能这样写了,上线前改动代码是有风险的,怎么解决这个问题呢?
可不可以开发环境中依旧用本地请求地址,如果有个转发机制,可以帮助我们把对api
下的所有json
文件的请求转发到本地的mock
文件夹下,这样不就可以了吗?
Vue
的脚手架里提供了一个proxy的代理功能,通过这个功能,可以实现上面的构想。
在config/index.js
里有一个proxyTable
,对它进行相应的配置就行。
解释一波。
当请求
api
这个目录的时候,把请求转发到当前服务器的8080
端口上,将路径做一个替换,一旦请求的地址是以api
开头,就替换成请求本地的mock
这个文件夹下。
这个功能实际上是webpack-dev-server
提供的,并不真正是Vue
提供的。
改完配置项文件的时候,记得要重新运行一下服务器~
传递数据
上面已经用axios
获取了数据,现在要将数据传给各个组件了。
先去home
组件,也就是首页这个父组件。
给各个组件传值,其实也就是我们之前说的父组件给子组件传值。
举个栗子:
1.父组件内,创建一个data
,给子组件通过绑定属性的形式传值(默认值为空)
2.子组件通过props接收
props接收,然后更改绑定的模板
3.回到父组件,创建数据的存放变量。
拿到数据内容
分解一下步骤:
1)让
res = res.data
,是为了让json文件内容 = res,如下图,要取得city
的值,实际上是res.data.data.city
,经过这个赋值步骤后,再拿到city
的内容的表达式就是res.data.city
。2)做个判断,如果后端正确的返回了结果,并且
res
有内容项,再执行赋值操作。3)获取内容赋值。 后面的操作就是拿到内容,然后赋值对应的值,
this.city = data.city
(这里的data = res.data
,做了处理)将res=res.data
这样就拿到了内容了。
整个流程是,获取到city
的内容后,传给了父组件data
里的city
,然后再传给了子组件(通过属性绑定),子组件接收了这个city
,然后就能拿到这个值了。
子组件内接收list属性,类型为数组,循环的也是list的内容
【子组件之前的data里的数据记得删除】
一个小小的tips:
在swiper
组件这里可能会有一个小bug,获取到ajax
数据之后,展示的第一页是最后一个,而不是索引最靠前的那个,为什么会这样呢?
swiper
最初创建的时候是通过空数组创建的(默认值),当ajax获取完之后,swiperList
变成真正的数据项,再传给homeSwiper
这个组件的时候,list
才获取到新数据,重新渲染了新数据对应的很多幻灯片,就是因为初始化创建是根据空数组创建的,才会导致默认显示的是最后一张幻灯片。
怎么解决呢?
让swiperList
最初的创建不由空数组,而由完整的数据来创建。写一个v-if="list.length"
,当这个时候传递过来的list是个空数组的时候,swiper
不会被创建,只有当真正数据过来之后,swiper
才会创。
但是这样的代码不是很优雅,模板中应该尽量减少逻辑性的代码。
所以在data下增加一个computed计算属性。做一下逻辑处理
模板中再更改一下:
更改一下
关于axios拦截器
这部分内容是2018年7月25日
的更新,之前自己只会引用axios
,进行get
或者post
之类的请求。后来因为业务需求,有的时候需要对请求和响应进行拦截。
比如说,在每次请求都需要加一个source
号,来告诉是xxx渠道的请求,因为可能由于业务原因,对不同渠道的数据进行了划分。难道我们每一次请求接口,都要首先从缓存中拿到source
的值,然后再和参数拼接起来一起传过去?
这里就可以用到我们所说的请求拦截了。
也就是封装一个axios
,然后在请求之前做一个拦截,将参数多加一个source
上去,这样就在封装的时候做一次操作就行了,不用每次请求接口都去拿source
。
同样的,响应也能做拦截,众所周知,返回的resultCode
为一个约定的正确值时,表示data
是正确返回,但是有的时候不一定有正确的返回,比如说source
、code
失效了,之类的,这个时候接口会返回一个特定的值,例如我和后台约定的是errorCode
返回的如果是LASEB111
,就跳转到特定的错误提示页。
我们同样可以统一做拦截,然后一次代码就能让所有的请求只要出现这种错误码。就直接跳转到错误提示页。而不是每一次请求接口,再用多个if...else
来对错误码做一次次的判断。
贴一下代码:
全局配置
到这里还没完,我们仅仅是封装了自己的
axios
,但是还没有引入。因为这是我们自己封装的axios
,引入的时候就像引入插件一样。首先引入需要的,在这里我们还配置了一些东西,比如请求的时候的
loading
的效果,还有伴随一些弹窗提示。我用的是mint-ui
的弹窗和loading
效果。小伙伴可以配置自己相应ui
的效果。
引入需要的
请求成功时
请求失败时
记得将方法添加到
vue
的原型链上。最后最后,还有一个地方。
main.js里要记得引入然后use
ヾ(◍°∇°◍)ノ゙
网友评论