一、queryString
有的时候,我们可能也会用到 queryString 。
queryString 即 ?sort=desc 这种形式。
大批量数据都是通过后端进行处理,除非数据量很少。此处后端通过参数sort进行排序。
<!-- 使用v-model 绑定排序,并使用 watch进行监听-->
<select v-model="sort">
<option value="desc">从高到低</option>
<option value="asc">从低到高</option>
</select>
可以通过v-bind,然后通过change事件监听数据的变化;也可以通过watch监听数据的变化
axios里通过params配置将queryString发送到后端;(如果将数据放到data中,需要使用post请求,且是通过正文发送的请求)
<template>
<div class="home">
<h2>商品列表——首页</h2>
<!-- 使用v-model 绑定排序,并使用 watch进行监听-->
<select v-model="sort">
<option value="desc">从高到低</option>
<option value="asc">从低到高</option>
</select>
<ul class="item-list">
<li class="head">
<span>名称</span>
<span>品牌</span>
<span>价格</span>
<span>操作</span>
</li>
<li v-for="item of items" :key="item.id">
<span>{{item.name}}</span>
<span>{{item.vendor}}</span>
<span>{{item.price|RMB}}</span>
<span>
<!-- 注意:用v-bind方式,则属性值里必须是表达式-->
<!-- <router-link :to="`/item/${item.id}`">查看详情</router-link> -->
<!-- 以动态路由形式赋值,注意一定要以v-bind形式进行绑定,后台路由需要设置name:'item' -->
<router-link :to="{name: 'item', params:{id: item.id}}">查看详情</router-link>
</span>
</li>
</ul>
</div>
</template>
<script>
import axios from "axios";
import RMB from "@/filter/RMB";
export default {
name: "Home",
// 注册过滤器
filters: {
RMB
},
// 注意是在created生命周期中发送请求(组件渲染完成后)
data() {
return {
items: [],
sort: "desc"
};
},
async created() {
// 注意请求需要使用async await
await this.getItems();
},
// 使用watch监听组件变化,注意watch是对象
watch: {
sort() {
// 监听到sort发生变化后重新发起请求(但是这样不会在url上带上sort=desc不利于分享状态)
await this.getItems();
},
},
methods:{
async getItems(){
await axios({
// 通过axios发起异步代理请求
url: "/api/items",
// 此处为发送给后台请求地址加上queryString
params: {
sort: this.sort
}
}).then(res => {
// 将获取到的值设置到data中
this.items = res.data;
});
}
},
};
</script>
<style>
ul {
margin: 0;
padding: 0;
}
li {
list-style: none;
}
.item-list li {
padding: 10px;
display: flex;
justify-content: space-between;
height: 30px;
line-height: 30px;
border-bottom: 1px dotted #333;
}
.item-list li.head {
font-weight: bold;
}
.item-list li span {
min-width: 200px;
}
</style>
问题:虽然能实现对价格进行排序,但是 url上不会带上?sort=desc,如果将链接复制给别人,打开网页时仍然是默认排序,不是分享时排好序的,所以不利于分享状态(地址中带上排序参数及值)
1.1 $route.query
我们可以通过路由对象 $route 的 query 属性来获取 queryString
...
computed: {
sort: {
get() {
return this.$route.query.sort || 'desc';
}
}
}
...
1.2 编程式导航
有的时候,我们可能需要用到编程的方式来导航(跳转),而不是点击链接。如:当 sort
发生改变的时候跳转
push()方法中可以使用字符串拼接url形式,也可以使用对象进行传参
...
computed: {
sort: {
get() {
return this.$route.query.sort || 'desc';
},
set(newVal) {
this.$router.push({
name: 'home',
query: {
sort: newVal
}
});
}
}
}
...
示例:
watch: {
sort() {
// 监听到sort发生变化后重新发起请求(但是这样不会在url上带上sort=desc不利于分享状态)
// await this.getItems();
// 然后通过编程式导航进行跳转(可以拼接字符串,也可以对象形式传参)
// this.$router.push('/?sort=' + this.sort);
this.$router.push({
// 此处name对应路由中Home组件的路由name
name: "home",
// 此处为地址栏上地址加上queryString
query: {
sort: this.sort
}
});
},
问题:发现地址栏变化了,但是页面并没有更新。这涉及到路由组件复用问题。
二、路由组件的复用
为了提高性能,增强路由组件的复用,当路由切换使用的是同一个组件的时候,则会复用该路由组件,而不是销毁重建,这个时候,我们就需要通过 watch 或者 路由相关的生命周期函数来处理切换路由导致的变化
2.1 watch
如果切换的路由复用了组件,这个时候,我们可以使用 watch 监听 $route
watch: {
$route(to, from) {
console.log('$route');
}
}
-
to : 改变之后的 $route 对象
-
from : 改变之前的 $route 对象
watch: {
sort() {
// 监听到sort发生变化后重新发起请求(但是这样不会在url上带上sort=desc不利于分享状态)
// await this.getItems();
// 然后通过编程式导航进行跳转(可以拼接字符串,也可以对象形式传参)
// this.$router.push('/?sort=' + this.sort);
this.$router.push({
// 此处name对应路由中Home组件的路由name
name: "home",
// 此处为地址栏上地址加上queryString
query: {
sort: this.sort
}
});
},
// 如果使用了路由守卫就不用监听$route
// 因为vue组件的复用性(vue在地址改变后,发现还是组件还是之前的组件,就不会进行重新创建),光使用queryString+this.$router.push还无法真正刷新页面
async $route() {
// 监听到变化时再发一次请求
await this.getItems();
}
},
完整代码:实现整个排序功能
<template>
<div class="home">
<h2>商品列表——首页</h2>
<!-- 使用v-model 绑定排序,并使用 watch进行监听-->
<select v-model="sort">
<option value="desc">从高到低</option>
<option value="asc">从低到高</option>
</select>
<ul class="item-list">
<li class="head">
<span>名称</span>
<span>品牌</span>
<span>价格</span>
<span>操作</span>
</li>
<li v-for="item of items" :key="item.id">
<span>{{item.name}}</span>
<span>{{item.vendor}}</span>
<span>{{item.price|RMB}}</span>
<span>
<!-- 注意:用v-bind方式,则属性值里必须是表达式-->
<!-- <router-link :to="`/item/${item.id}`">查看详情</router-link> -->
<!-- 以动态路由形式赋值,注意一定要以v-bind形式进行绑定,后台路由需要设置name:'item' -->
<router-link :to="{name: 'item', params:{id: item.id}}">查看详情</router-link>
</span>
</li>
</ul>
</div>
</template>
<script>
import axios from "axios";
import RMB from "@/filter/RMB";
export default {
name: "Home",
// 注册过滤器
filters: {
RMB
},
// 注意是在created生命周期中发送请求(组件渲染完成后)
data() {
return {
items: [],
sort: "desc"
};
},
async created() {
// 注意this.sort获取位置,是在组件渲染完后立即赋值,否则有可能没有获取到,从而产生异步问题
this.sort = this.$route.query.sort || this.sort;
// 注意请求需要使用async await
await this.getItems();
},
// 使用watch监听组件变化,注意watch是对象
watch: {
sort() {
// 监听到sort发生变化后重新发起请求(但是这样不会在url上带上sort=desc不利于分享状态)
// await this.getItems();
// 然后通过编程式导航进行跳转(可以拼接字符串,也可以对象形式传参)
// this.$router.push('/?sort=' + this.sort);
this.$router.push({
// 此处name对应路由中Home组件的路由name
name: "home",
// 此处为地址栏上地址加上queryString
query: {
sort: this.sort
}
});
},
// 如果使用了路由守卫就不用监听$route
// 因为vue组件的复用性(vue在地址改变后,发现还是组件还是之前的组件,就不会进行重新创建),光使用queryString+this.$router.push还无法真正刷新页面
async $route() {
// 监听到变化时再发一次请求
await this.getItems();
}
},
methods:{
async getItems(){
await axios({
// 通过axios发起异步代理请求
url: "/api/items",
// 此处为发送给后台请求地址加上queryString
params: {
sort: this.sort
}
}).then(res => {
// 将获取到的值设置到data中
this.items = res.data;
});
}
},
};
</script>
<style>
ul {
margin: 0;
padding: 0;
}
li {
list-style: none;
}
.item-list li {
padding: 10px;
display: flex;
justify-content: space-between;
height: 30px;
line-height: 30px;
border-bottom: 1px dotted #333;
}
.item-list li.head {
font-weight: bold;
}
.item-list li span {
min-width: 200px;
}
</style>
但是我们可以使用 vue-router 提供路由守卫 (路由有关的生命周期函数)来处理路由有关的业务逻辑(见下一篇)