Vue本身并不提供Ajax的功能。
我们可以使用原生的JavaScript或JQuery来完成Ajax的操作。
但是Vue推荐使用axios,它是promise风格的(复习:回调地狱),飞哥觉得同学们也可以了解一下:
axios现阶段可以直接引用js文件:
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
引入axios之后我们就能得到一个全局变量:axios(F12演示)
和JQuery一样,首先提供一个基本/全能操作函数:axios(config),其中的config可以包括:
method: "get", params: { enrolled: 1, graduate: true }
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
以及:
通过form文件表单拿到文件:(复习:事件和ref)
<form id="yz-hello"> <input type="file" name="icon" id="" v-on:change="upload" ref="icon"> </form>
我们可以:
var form = this.$refs.icon.parentElement, //form表单元素 formData = new window.FormData(form); //注意构造函数参数,name
var icon = this.$refs.icon, formData = new window.FormData(); //注意window.不能省略 formData.append('icon', icon.files[0])
@想一想@:为什么window.不能省略?
早期版本中还需要在config中添加HTTP Header:
headers: { 'Content-Type': 'multipart/form-data' },
利用后台WebApi演示:能收到上传文件
config中还可以配置onUploadProgress,指定文件上传中的事件:
onUploadProgress: function (progressEvent) {//@想一想@有没有坑? console.log('onUploadProgress...');//在文件开始上传时触发 },
@试一试@:能不能将信息显示在HTML元素上?
<small v-show="inProgress">上传中……</small>
data: { inProgress: false },onUploadProgress中:
this.inProgress = true; //行不行?
注意:这里的this指代的是谁?!
axios推荐总是使用箭头函数:
onUploadProgress: (progressEvent) => { this.inProgress = true; },
最后,可以利用progressEvent获取上传的进度:
//已经上传大小/总上传大小 this.percentage = progressEvent.loaded / progressEvent.total;
演示:为了效果需要使用大文件,所以需要通过web.config的上传文件大小限制
axios.request()返回的是一个promise对象,所以可以then(handler);handler作为回调函数,带一个参数(通常命名为response),包含的信息按有用性依次是:
后台WebApi演示:显示上传的文件
需要一个img标签:
<img v-if="shown" :src="imgSrc" alt="图片" />imgSrc是vue data,在then()的回调函数里赋值:
this.imgSrc = response.data;但注意这个shown,不需要设置在vue data里面,可以使用计算属性(复习)
computed: { shown: () => { return Boolean(this.imgSrc); } },
如果Ajax请求出现异常,就会调用catch()中的回调函数。该函数带一个参数(通常命名error),根据错误发生的阶段,又包含以下信息:
if (error.response) { console.log(error.response.data); console.log(error.response.status); console.log(error.response.headers); } else if (error.request) { console.log(error.request); } else { console.log('Error', error.message); }
因为ES标准和浏览器支持的原因,axios官方文档里面并没有提到finally()。
但现在主流的浏览器中已经能够使用finally了(没有回调参数参数);注意这不是因为axios,而是因为Promise。
还可以在config中指定:timeout,
timeout: 500,
单位毫秒,超时后就直接走catch的error.request。
其实,服务器端一般也有timeout,但axios中设置timeout给前端开发人员更多控制,在某些特殊情况下应该有用,比如:按钮被点击后禁用,过一段时间就解禁。
对比演示:访问一个
PS:axios中还可以配置cancelToken取消请求,用得很少,略
实际开发中我们经常需要碰到这样的场景:
如果是JQuery,我们就会形成回调地狱;但使用axios,我们能够promise连缀。
后一个then()一定是在前一个then()执行完成之后才执行。
所以可以很放心的使用前一个then里面修改过的vue data:
}).then((response) => { this.imgSrc = response.data; }).then((response) => { console.log(this.imgSrc); })
但是,在某些特殊场景下,没有/不需要vue data做中介,你还能拿到前面一个then()里的值么?
}).then((response) => { //假设没有this.imgSrc作为中介? return response.data }).then((data) => { console.log(data); })
等等,我第2个then里面是要发起Ajax请求的,而且还有第3个then呢?
}).then((response) => { axios.request({ url: "", params: { path: this.imgSrc } }) .then(/*这不又地狱回调了么?*/) })axios中可以在then()后面继续接then()。但是,注意:前面一个then里面要加一个return
}).then((response) => { return axios.request({ url: "/api/Student/2"} }); }).then((response) => { //response代表上一次请求的结果 console.log(response.data); })
和JQuery一样,axios也根据请求的method不同,提供一些简写方法:
axios.request("/api/Student", { method: "post" //指定method,默认是get })
axios.get("/api/Student", { //确定是get请求 params: { name: '大飞哥' } })
axios.post("/api/Student/2", { //确定是post请求 data: { name: '大飞哥' } })
类似的还有put()、delete()等……(略)
还可以使用all()一次性发出多个请求:
axios.all([//注意方括号 axios.get('/api/Student'), axios.get('/api/Student/1'), axios.get('/api/Student/2') ]).then(
注意:这里的all()和then()...then()是不一样的:
在request中作为参数的config,只能影响本次提交。
如果要影响“所有”的axios提交,需要进行全局设置(又被称之为“默认配置”)。
axios.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded'; axios.defaults.baseURL = 'https://17bang.ren';//可理解为url前缀注意不要将其设置到:axios.defaults.post.headers里面(但我也不知道这玩意儿究竟干啥用的,详见源代码演示)
config.headers = utils.merge( config.headers.common || {}, config.headers[config.method] || {}, config.headers ); utils.forEach( ['delete', 'get', 'head', 'post', 'put', 'patch', 'common'], function cleanHeaderConfig(method) { delete config.headers[method]; } );有时候我们会想让设置只影响“一部分”的请求,这时候我们可以
let ax = axios.create({ headers: { 'Content-Type': 'multipart/form-data' } });
ax.post("/api/Student", { //注意不是axios
这样,凡是由ax发起的请求都会默认使用其创建时的配置。
你也一样可以在已生成的ax上设置defaults:
ax.defaults.headers['Content-Type'] = 'application/x-www-form-urlencoded';
网上有一种说法:
配置会以一个优先顺序进行合并
注意不要误解,准确来说,应该是:
除了全局配置,有时候我们还希望对所有/部分的请求做一些额外的(request发起/得到respons前)处理。这就需要使用拦截器(interceptor)
axios.interceptors.request.use(function (config) { //.... 一般就是配置config,比如添加/修改baseURL、header键值对等 return config; }, function (error) { // 当请求出现错误 //.... return Promise.reject(error); });
axios.interceptors.response.use(function (response) { //.... return response; }, function (error) {// 当响应错误 //.... 一般就是:1. 提示用户;2.记录并传回错误信息 return Promise.reject(error); });
通常都用于设置vue data。可以是:
mounted: function () { axios.get("/Student/23").then(response => { this.sname = response.data.sname; }) }
其实因为vue的响应式渲染,不用担心then()的异步执行。
比如content-type、response type/encoding究竟选什么?
一句话:需要前后端协商/协调决定。
前后端分离能够顺利有效进行的一个核心要件:良好的API。
纯前端通过mock.js或模拟静态HTML片段页面(全栈需要完整实现),通过axios完成以下功能:
在文章发布页面,实现添加新系列的功能。注意:已有系列数据从后台获得
多快好省!前端后端,线上线下,名师精讲
更多了解 加: