Vue(五)——vue-router(queryString)_商品价格排序

89 篇文章 7 订阅

一、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

我们可以通过路由对象 $routequery 属性来获取 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 提供路由守卫 (路由有关的生命周期函数)来处理路由有关的业务逻辑(见下一篇)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值