Vue 0基础学习路线(18)—— 图解深度详述vue的queryString和$route.query及路由组件的复用、watch的使用及详细案例(附详细案例代码解析过程及版本迭代过程)

1. 重点提炼

  • queryString
    • $route.query
  • 路由组件的复用
    • watch

2. queryString

有的时候,我们可能也会用到 queryString

<select v-model="sort">
  <option value="desc">从高到低</option>
  <option value="asc">从低到高</option>
</select>

2.1 $route.query

我们可以通过路由对象 $routequery 属性来获取 queryString

...
computed: {
	sort: {
		get() {
      return this.$route.query.sort || 'desc';
    }
	}
}
...

2.2 编程式导航

有的时候,我们可能需要用到编程的方式来导航(跳转),而不是点击链接。如:当 sort 发生改变的时候跳转

...
computed: {
	sort: {
		get() {
      return this.$route.query.sort || 'desc';
    },
		set(newVal) {
			this.$router.push({
        name: 'home',
        query: {
          sort: newVal
        }
      });
		}
	}
}
...

3. example01

我们对商品进行排序:最好不要用内部状态处理这件事,因为如果分享链接,无法保留分享前的状态。

所以最好的方式是用路由跳转

3.1 example01-1

我们可以用watch监听sort数据变化

\app\src\views\Home.vue

<template>
    <div>
        <h2>商品列表</h2>
        <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>
            </li>
            <li v-for="item of items" :key="item.id">
                <span>
                    <router-link :to='"/view/" + item.id'>{{item.name}}</router-link>
                </span>
                <span>{{item.price|RMB}}</span>
                <span>
                    <button>添加到购物车</button>
                </span>
            </li>
        </ul>
    </div>
</template>

<script>
    import * as apis from '@/apis'
    import {RMB} from "@/filters/RMB";

    export default {
        name: "Home",

        data() {
            return {
                sort: 'desc',
                items: []
            }
        },

        async created() {
            let rs = await apis.getItems();

            this.items = rs.data;
        },

        // 局部过滤器引入,挂载到filters
        filters: {
            RMB
        },

        watch: {
            // 监听sort数据变化
            sort() {
                console.log('......')
            }
        }
    }
</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>

在这里插入图片描述

参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a1.82
Branch: branch05

commit description:a1.82(example01-1——watch监听sort数据变化)

tag:a1.82

3.2 example01-2

或者绑定change事件 => 就没必要进行双向绑定,直接用v-bind了。

\app\src\views\Home.vue

<template>
    <div>
        <h2>商品列表</h2>
        <select @change="changeSort" :value="sort">
            <option value="desc">从高到低</option>
            <option value="asc">从低到高</option>
        </select>

        <ul class="item-list">
            <li class="head">
                <span>名称</span>
                <span>价格</span>
                <span>操作</span>
            </li>
            <li v-for="item of items" :key="item.id">
                <span>
                    <router-link :to='"/view/" + item.id'>{{item.name}}</router-link>
                </span>
                <span>{{item.price|RMB}}</span>
                <span>
                    <button>添加到购物车</button>
                </span>
            </li>
        </ul>
    </div>
</template>

<script>
    import * as apis from '@/apis'
    import {RMB} from "@/filters/RMB";

    export default {
        name: "Home",

        data() {
            return {
                sort: 'desc',
                items: []
            }
        },

        async created() {
            let rs = await apis.getItems();

            this.items = rs.data;
        },

        // 局部过滤器引入,挂载到filters
        filters: {
            RMB
        },

        // watch: {
        //     // 监听sort数据变化
        //     sort() {
        //         console.log('......')
        //     }
        // }

        methods: {
            changeSort({target: {value}}) {
                this.$router.push('/?sort=' + value)
            }
        }
    }
</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>

在这里插入图片描述

参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a1.83
Branch: branch05

commit description:a1.83(example01-2——绑定change事件监听sort数据变化)

tag:a1.83

3.3 example01-3

路由配置还可以给路由起名字(和给组件起名称一样),方便去复用。

\app\src\router\index.js

import Vue from 'vue';
import VueRouter from 'vue-router';

import Home from '@/views/Home';
import About from '@/views/About';
import Detail from '@/views/Detail';

Vue.use(VueRouter);

let router = new VueRouter({
    mode: 'history',
    routes: [
        {
            path: '/',
            name: 'home',
            component: Home
        },
        {
            path: '/about',
            name: 'about',
            component: About
        },
        {
            path: '/view/:id',
            name: 'view',
            component: Detail
        }
    ]
});

export default router;

router-link :to='"/view/" + item.id' 拼(字符串)路由跳转的url易出错,可以用(路由)对象去描述

这个对象会自动解析成url格式

name属性就是对应我们要跳转的页面路由的name

params属性配置就是后面参数了 => item.id

router-link :to="{name: 'view', params: {id: item.id}}"

this.$router.push => 配置对象 =>

name属性就是对应我们要跳转的页面路由的name

query 其实就是queryString将其赋值给sort

\app\src\views\Home.vue

<template>
    <div>
        <h2>商品列表</h2>
        <select @change="changeSort" :value="sort">
            <option value="desc">从高到低</option>
            <option value="asc">从低到高</option>
        </select>

        <ul class="item-list">
            <li class="head">
                <span>名称</span>
                <span>价格</span>
                <span>操作</span>
            </li>
            <li v-for="item of items" :key="item.id">
                <span>
                    <router-link :to="{name: 'view', params: {id: item.id}}">{{item.name}}</router-link>
                </span>
                <span>{{item.price|RMB}}</span>
                <span>
                    <button>添加到购物车</button>
                </span>
            </li>
        </ul>
    </div>
</template>

<script>
    import * as apis from '@/apis'
    import {RMB} from "@/filters/RMB";

    export default {
        name: "Home",

        data() {
            return {
                sort: 'desc',
                items: []
            }
        },

        async created() {
            let rs = await apis.getItems();

            this.items = rs.data;
        },

        // 局部过滤器引入,挂载到filters
        filters: {
            RMB
        },

        // watch: {
        //     // 监听sort数据变化
        //     sort() {
        //         console.log('......')
        //     }
        // }

        methods: {
            changeSort({target: {value}}) {
                this.$router.push({
                    name: 'home',
                    query: {
                        sort: value
                    }
                });
            }
        }
    }
</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>

router-link 成功生成 正确的href

在这里插入图片描述

发现问题:页面未发生任何渲染

在这里插入图片描述

参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a1.84
Branch: branch05

commit description:a1.84(example01-3——路由配置名称可复用但出了问题)

tag:a1.84

4. 路由组件的复用

为了提高性能,增强路由组件的复用,当路由切换(页面跳转)使用的是同一个组件的时候,则会复用该路由组件,而不是销毁重建,这个时候,我们就需要通过 watch 或者 路由相关的生命周期函数来处理切换路由导致的变化。

所以上面的例子,我们始终还在Home路由(组件)上,所以为了节省性能,Home组件是不会销毁重建的,而是复用。这个时候我们再监听sort的变化是没有任何用的,因为仅仅是地址栏发生了变化,数据实际没有变化。

所以实际上我们应该监听 $route,它代表当前匹配的路由对象,地址发生了变化,它必然会变化。

4.1 watch

如果切换的路由复用了组件,这个时候,我们可以使用 watch 监听 $route(当前路由匹配的对象必然改变)

watch: {
  $route(to, from) {
      console.log('$route');
  }
}
  • to: 改变之后的 $route 对象
  • from: 改变之前的 $route 对象

但是我们可以使用 vue-router 提供路由守卫 (路由有关的生命周期函数)来处理路由有关的业务逻辑

5. example02

5.1 exmaple02-1

我们可以打印看看$route(to, from)中的参数。

\app\src\views\Home.vue

        watch: {
            $route(to, from) {
                console.log(from);
                console.log(to);
            }
        },

进入页面后的query为空,我们切换从低到高

在这里插入图片描述

再切换到从高到低

在这里插入图片描述

参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a1.85
Branch: branch05

commit description:a1.85(example02-1——打印看看$route(to, from)中的参数)

tag:a1.85

5.2 exmaple02-2

监听$route,发生变化,重新发请求即可,后端有排序的接口,这里我们直接调用即可,我们改一下之前封装的接口即可。

\app\src\apis\index.js

import axios from 'axios'
import URLS from './URLS'
 
// export async function getItems() {
export async function getItems(sort) {
    let rs = await axios({
        url: URLS.ITEMS + '?sort=' + sort
        // url: URLS.ITEMS
    });
 
    return rs;
}
 
 
export async function getItem(id) {
 
    let rs = await axios({
        url: URLS.ITEM + '/' + id
    });
 
    return rs;
}

实际上我们把sort定义在data中,我们是从url中获取的,我们实际在watch的时候需要更新它。

并且页面一开始加载出来的时候,做初始化。

\app\src\views\Home.vue

<template>
    <div>
        <h2>商品列表</h2>
        <select @change="changeSort" :value="sort">
            <option value="desc">从高到低</option>
            <option value="asc">从低到高</option>
        </select>

        <ul class="item-list">
            <li class="head">
                <span>名称</span>
                <span>价格</span>
                <span>操作</span>
            </li>
            <li v-for="item of items" :key="item.id">
                <span>
                    <router-link :to="{name: 'view', params: {id: item.id}}">{{item.name}}</router-link>
                </span>
                <span>{{item.price|RMB}}</span>
                <span>
                    <button>添加到购物车</button>
                </span>
            </li>
        </ul>
    </div>
</template>

<script>
    import * as apis from '@/apis'
    import {RMB} from "@/filters/RMB";

    export default {
        name: "Home",

        data() {
            return {
                sort: 'desc',
                items: []
            }
        },

        async created() {
            this.sort = this.$route.query.sort || 'desc';
            let rs = await apis.getItems(this.sort);

            this.items = rs.data;
        },

        // 局部过滤器引入,挂载到filters
        filters: {
            RMB
        },

        watch: {
            async $route(to, from) {
                this.sort = this.$route.query.sort || 'desc';
                let rs = await apis.getItems(this.sort);

                this.items = rs.data;
            }
        },

        methods: {
            changeSort({target: {value}}) {
                this.$router.push({
                    name: 'home',
                    query: {
                        sort: value
                    }
                });
            }
        }
    }
</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>

在这里插入图片描述

参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a1.86
Branch: branch05

commit description:a1.86(example02-2——实现排序切换)

tag:a1.86

5.3 exmaple02-3

有冗余代码极为相似,得优化一下。 => 封装

\app\src\views\Home.vue

<template>
    <div>
        <h2>商品列表</h2>
        <select @change="changeSort" :value="sort">
            <option value="desc">从高到低</option>
            <option value="asc">从低到高</option>
        </select>

        <ul class="item-list">
            <li class="head">
                <span>名称</span>
                <span>价格</span>
                <span>操作</span>
            </li>
            <li v-for="item of items" :key="item.id">
                <span>
                    <router-link :to="{name: 'view', params: {id: item.id}}">{{item.name}}</router-link>
                </span>
                <span>{{item.price|RMB}}</span>
                <span>
                    <button>添加到购物车</button>
                </span>
            </li>
        </ul>
    </div>
</template>

<script>
    import * as apis from '@/apis'
    import {RMB} from "@/filters/RMB";

    export default {
        name: "Home",

        data() {
            return {
                sort: 'desc',
                items: []
            }
        },

        async created() {
            this.getItems();
        },

        // 局部过滤器引入,挂载到filters
        filters: {
            RMB
        },

        watch: {
            async $route(to, from) {
                this.getItems();
            }
        },

        methods: {
            changeSort({target: {value}}) {
                this.$router.push({
                    name: 'home',
                    query: {
                        sort: value
                    }
                });
            },

            async getItems() {
                this.sort = this.$route.query.sort || 'desc';
                let rs = await apis.getItems(this.sort);

                this.items = rs.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>

在这里插入图片描述

参考:https://https://github.com/6xiaoDi/blog-vue-Novice/tree/a1.87
Branch: branch05

commit description:a1.87(example02-3——实现排序切换-代码优化)

tag:a1.87



(后续待补充)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值