一、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 awaitawait this.getItems();},// 使用watch监听组件变化,注意watch是对象watch: {sort() {// 监听到sort发生变化后重新发起请求(但是这样不会在url上带上sort=desc不利于分享状态)await this.getItems();},},methods:{async getItems(){await axios({// 通过axios发起异步代理请求url: "/api/items",// 此处为发送给后台请求地址加上queryStringparams: {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组件的路由namename: "home",// 此处为地址栏上地址加上queryStringquery: {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组件的路由namename: "home",// 此处为地址栏上地址加上queryStringquery: {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 awaitawait this.getItems();},// 使用watch监听组件变化,注意watch是对象watch: {sort() {// 监听到sort发生变化后重新发起请求(但是这样不会在url上带上sort=desc不利于分享状态)// await this.getItems();// 然后通过编程式导航进行跳转(可以拼接字符串,也可以对象形式传参)// this.$router.push('/?sort=' + this.sort);this.$router.push({// 此处name对应路由中Home组件的路由namename: "home",// 此处为地址栏上地址加上queryStringquery: {sort: this.sort}});},// 如果使用了路由守卫就不用监听$route// 因为vue组件的复用性(vue在地址改变后,发现还是组件还是之前的组件,就不会进行重新创建),光使用queryString+this.$router.push还无法真正刷新页面async $route() {// 监听到变化时再发一次请求await this.getItems();}},methods:{async getItems(){await axios({// 通过axios发起异步代理请求url: "/api/items",// 此处为发送给后台请求地址加上queryStringparams: {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 提供路由守卫 (路由有关的生命周期函数)来处理路由有关的业务逻辑(见下一篇)