异步查询数据,自然是通过ajax查询,大家首先想起的肯定是jQuery。但jQuery与MVVM的思想不吻合,而且ajax只是jQuery的一小部分。因此不可能为了发起ajax请求而去引用这么大的一个库。
官网:https://www.kancloud.cn/yunye/axios/234845
1、axios 入门
Vue 官方推荐的 ajax 请求框架叫做:axios,看下demo:
axios 的 Get 请求语法:
axios.get("/item/category/list?pid=0") // 请求路径和请求参数拼接
.then(function(resp){
// 成功回调函数
})
.catch(function(){
// 失败回调函数
})
// 参数较多时,可以通过params来传递参数
axios.get("/item/category/list", {
params:{
pid:0
}
})
.then(function(resp){})// 成功时的回调
.catch(function(error){})// 失败时的回调
axios 的 POST 请求语法:
比如新增一个用户
axios.post("/user",{
name:"Jack",
age:21
})
.then(function(resp){})
.catch(function(error){})
- 注意,POST 请求传参,不需要像 GET 请求那样定义一个对象,在对象的 params 参数中传参。post() 方法的第二个参数对象,就是将来要传递的参数
PUT 和 DELETE 请求与 POST 请求类似
2、axios 的全局配置
而在我们的项目中,已经引入了 axios,并且进行了简单的封装,在 src 下的 http.js 中:
http.js 中对 axios 进行了一些默认配置:
import Vue from 'vue'
import axios from 'axios'
import config from './config'
// config中定义的基础路径是:http://api.leyou.com/api
axios.defaults.baseURL = config.api; // 设置axios的基础请求路径
axios.defaults.timeout = 2000; // 设置axios的请求时间
// axios.interceptors.request.use(function (config) {
// // console.log(config);
// return config;
// })
axios.loadData = async function (url) {
const resp = await axios.get(url);
return resp.data;
}
Vue.prototype.$http = axios; // 将 axios 赋值给 Vue 原型的 $http 属性,这样所有 vue 实例都可使用该对象
-
http.js 中导入了 config 的配置,还记得吗?
-
http.js 对 axios 进行了全局配置:
baseURL=config.api
,即http://api.leyou.com/api
。因此以后所有用 axios 发起的请求,都会以这个地址作为前缀。 -
通过
Vue.property.$http = axios
,将axios
赋值给了 Vue原型中的$http
。这样以后所有的 Vue 实例都可以访问到 $http,也就是访问到了 axios 了。
3、测试一下:
我们在组件MyBrand.vue
的getDataFromServer
方法,通过$http
发起get
请求,测试查询品牌的接口,看是否能获取到数据:
网络监视:
控制台结果:
可以看到,在请求成功的返回结果 response 中,有一个 data 属性,里面就是真正的响应数据。
响应结果中与我们设计的一致,包含3个内容:
- total:总条数,目前是165
- items:当前页数据
- totalPage:总页数,我们没有返回
4、异步加载品牌数据
5、完成分页和过滤
分页
现在我们实现了页面加载时的第一次查询,你会发现你点击分页或搜索不会发起新的请求,怎么办?
虽然点击分页,不会发起请求,但是通过浏览器工具查看,会发现 pagination 对象的属性一直在变化:
我们可以利用 Vue 的监视功能:watch,当 pagination 发生改变时,会调用我们的回调函数,我们在回调函数中进行数据的查询即可!
具体实现:
成功实现分页功能:
过滤
分页实现了,过滤也很好实现了。过滤字段对应的是search属性,我们只要监视这个属性即可:
查看网络请求:
页面结果:
6、完整代码
<template>
<v-card>
<v-card-title>
<v-btn color="primary" @click="addBrand">新增品牌</v-btn>
<!--搜索框,与search属性关联-->
<v-spacer/>
<v-text-field label="输入关键字搜索" v-model.lazy="search" append-icon="search" hide-details/>
</v-card-title>
<v-divider/>
<v-data-table
:headers="headers"
:items="brands"
:search="search"
:pagination.sync="pagination"
:total-items="totalBrands"
:loading="loading"
class="elevation-1"
>
<template slot="items" slot-scope="props">
<td>{{ props.item.id }}</td>
<td class="text-xs-center">{{ props.item.name }}</td>
<td class="text-xs-center"><img :src="props.item.image"></td>
<td class="text-xs-center">{{ props.item.letter }}</td>
<td class="justify-center layout">
<v-btn color="info">编辑</v-btn>
<v-btn color="warning">删除</v-btn>
</td>
</template>
</v-data-table>
</v-card>
</template>
<script>
import MyBrandForm from './MyBrandForm'
export default {
name: "my-brand",
data() {
return {
search: '', // 搜索过滤字段
totalBrands: 0, // 总条数
brands: [], // 当前页品牌数据
loading: true, // 是否在加载中
pagination: {}, // 分页信息
headers: [
{text: 'id', align: 'center', value: 'id'},
{text: '名称', align: 'center', sortable: false, value: 'name'},
{text: 'LOGO', align: 'center', sortable: false, value: 'image'},
{text: '首字母', align: 'center', value: 'letter', sortable: true,},
{text: '操作', align: 'center', value: 'id', sortable: false}
]
}
},
mounted() { // 渲染后执行
// 查询数据
this.getDataFromServer();
},
watch: {
pagination: { // 监视pagination属性的变化
deep: true, // deep为true,会监视pagination的属性及属性中的对象属性变化
handler() {
// 变化后的回调函数,这里我们再次调用getDataFromServer即可
this.getDataFromServer();
}
},
search: { // 监视搜索字段
handler() {
this.getDataFromServer();
}
}
},
methods: {
getDataFromServer() { // 从服务的加载数的方法。
// 发起请求
this.$http.get("/item/brand/page", {
params: {
key: this.search, // 搜索条件
page: this.pagination.page,// 当前页
rows: this.pagination.rowsPerPage,// 每页大小
sortBy: this.pagination.sortBy,// 排序字段
desc: this.pagination.descending// 是否降序
}
}).then(resp => { // 这里使用箭头函数
this.brands = resp.data.items;
this.totalBrands = resp.data.total;
// 完成赋值后,把加载状态赋值为false
this.loading = false;
})
}
}
}
</script>
<style scoped>
</style>