Vue 0基础学习路线-对比React(17)—— 图解深度详述vue动态路由和路由对象的使用及详细案例(附详细案例代码解析过程及版本迭代过程)

1. 重点提炼

  • 动态路由
    • $router
    • $route

2. 动态路由

有的时候,我们需要把满足某种规则的路由全部匹配到同一个组件,比如不同的商品的 url

/item/1
/item/2
/item/3
...

我们不可能为每一个商品都定义一个独立的组件,而是把它们都映射到同一个组件,同时 url 后面的部分为动态变化的部分,我们会在设计路由的时候进行特殊的处理

...
{
  path: '/item/:itemId',
  name: 'item',
  component: Item
}
...

其中 :itemId 表示匹配的 url 中动态部分内容,如上面的 1,2,3 等,同时该值将被赋值给路由的变量 itemId

// home.vue
<template>
  <div class="home">
    <h2>商品列表</h2>
    <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: "item", params:{itemId: item.id}}'>{{item.name}}</router-link>
          </span>
          <span>{{item.price|RMB}}</span>
          <span>
            <button>添加到购物车</button>
          </span>
      </li>
    </ul>
  </div>
</template>

<script>
import axios from 'axios';
import {RMB} from '@/filters/RMB';
export default {
  name: 'home',
  data() {
    return {
      items: []
    }
  },
  filters: {
    RMB
  },
  created() {
    axios({
      url: '/api/items'
    }).then(res => {
      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>

2.1 example01

2.1.1 example01-1

希望把不同的商品显示出来,这块的例子与我们之前在React中演示的例子是差不多的,可以对比看看。

<template>
    <div>
        <!--        Home-->
        <h2>商品列表</h2>
        <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: 'item', params: {id: item.id}}">{{item.name}}</router-link>
                </span>
                <span>{{item.price}}</span>
                <span>
                    <button>添加到购物车</button>
                </span>
            </li>
        </ul>
    </div>
</template>

<script>
    import * as apis from '@/apis'

    export default {
        name: "Home",

        data() {
            return {
                items: []
            }
        },

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

            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.78
Branch: branch05

commit description:a1.78(example01-1——商品列表框子)

tag:a1.78

2.1.2 example01-2

价格以为单位,可以写一个过滤转换为

这里用vue写一个过滤器(小迪就不再详述了,有问题请看之前的blog

\app\src\filters\RMB.js

export function RMB(val, flag='¥') {
    return flag + ' ' + (val / 100).toFixed(2);
}

\app\src\views\Home.vue

<template>
    <div>
        <!--        Home-->
        <h2>商品列表</h2>
        <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: 'item', 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'

    export default {
        name: "Home",

        data() {
            return {
                items: []
            }
        },

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

            this.items = rs.data;
        },

        // 局部过滤器引入,挂载到filters
        filters: {
            RMB
        }
    }
</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>

在这里插入图片描述

也可以设置美元符号:

<span>{{item.price|RMB('$')}}</span>

在这里插入图片描述

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

commit description:a1.79(example01-2——设置过滤器)

tag:a1.79

3. 路由对象

vue-router 会在组件中添加(注入)两个属性

  • $router:做与当前路由无关的操作,如跳转页面
  • $route:与当前路由相关操作

3.1 $router 对象

该对象其实就是 new VueRouter(…) 得到的路由对象,通过该对象我们可以访问全局路由信息,调用路由下的方法,比如:gobackpush

3.2 $route 对象

通过该对象可以访问(当前url)与当前路由匹配的信息(保存当前路由相关信息)

3.2.1 $route.params

获取动态路由有关的信息

// item.vue
<template>
    <div>
        <template v-if="item">
            <h2>商品详情 - {{item.name}}</h2>
            <dt>ID</dt>
            <dd>{{item.id}}</dd>
            <dt>名称</dt>
            <dd>{{item.name}}</dd>
            <dt>价格</dt>
            <dd>{{item.price|RMB}}</dd>
        </template>
        <template v-else>
            <h2>没有该商品信息</h2>
        </template>
    </div>
</template>
<script>
import axios from 'axios';
import {RMB} from '@/filters/RMB';
export default {
    name: 'item',
    data() {
        return {
            item: null
        }
    },
    filters: {
        RMB
    },
    created() {
        let itemId = Number(this.$route.params.itemId);
        if (itemId) {
            axios({
                url: `/api/item/${itemId}`
            }).then(res => {
                this.item = res.data;
            }).catch(err=>{});
        }
    }
}
</script>

3.3 example02

实现点击跳转详情页 => 获取用户点击选项的id值,需要从$route对象中获取

3.3.1 example02-1

\app\src\views\Detail.vue

<template>
    <div>
        商品详情
    </div>
</template>

<script>

    export default {
        name: "Detail",

        async created() {
            let id = this.$route.params.id;
        }
    }
</script>

<style scoped>

</style>

增加路由页面

\app\src\router\index.js

let router = new VueRouter({
    mode: 'history',    // hash \  history
 
    // 存放了 url 与 组件的映射关系
    routes: [
        // 每一个对象就是一组url与组件的对应
        {
            path: '/',
            component: Home,
        },
        {
            path: '/about',
            component: About
        },
        {
            path: '/view/:id',
            component: Detail
        }
    ]
});

点击首页对应项,跳转详情的router-link

vue05\app\src\views\Home.vue

            <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>{{item.price|RMB('$')}}</span>
                <span>
                    <button>添加到购物车</button>
                </span>
            </li>

$route.params.id => 即可获取到id了。

在这里插入图片描述

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

commit description:a1.80(example02-1——详情页框子)

tag:a1.80

3.3.2 example02-2

我们想在详情页获取数据,先拿到id再去找匹配(通过id发请求),路由对象(vue-router)提供了两个属性 =>

  • $router:做与当前路由无关的操作,如跳转页面 => 实际就是 new VueRouter 出来的实例对象。

    let router = new VueRouter({
        mode: 'history',    // hash \  history
     
        // 存放了 url 与 组件的映射关系
        routes: [
            // 每一个对象就是一组url与组件的对应
            {
                path: '/',
                component: Home,
            },
            {
                path: '/about',
                component: About
            },
            {
                path: '/view/:id',
                component: Detail
            }
        ]
    });
    
  • $route:与当前路由相关操作(与当前url匹配)

通过$route可以获取当前id,跳转界面(全局性操作,与当前路由无关的操作)利用$router对象。

实际在Reactrouter-dom中也有这两个东西,$router$route <=> historylocation

v-if根据 item是否有值,有的话就显示商品详情,否则显示没有该商品信息

\test01\app\src\views\Detail.vue

<template>
    <div>
        <!--        商品详情-->
        <template v-if="item">
            <h2>商品详情 - {{item.name}}</h2>
            <dt>ID</dt>
            <dd>{{item.id}}</dd>
            <dt>名称</dt>
            <dd>{{item.name}}</dd>
            <dt>价格</dt>
            <dd>{{item.price|RMB}}</dd>
        </template>
        <template v-else>
            <h2>没有该商品信息</h2>
        </template>
    </div>
</template>

<script>
    import {RMB} from "@/filters/RMB";

    export default {
        name: "Detail",

        data() {
            return {
                item: null
            }
        },

        filters: {
            RMB
        },

        async created() {
            let id = this.$route.params.id;
        }
    }
</script>

<style scoped>

</style>

还未id请求,因此没有商品信息。

在这里插入图片描述

配置后台的请求url

\app\src\apis\URLS.js

export default {
    'ITEMS': '/api/items',
    'ITEM': '/api/item'
}

\app\src\apis\index.js

import axios from 'axios'
import URLS from './URLS'

export async function getItems() {
    let rs = await axios({
        url: URLS.ITEMS
    });

    return rs;
}


export async function getItem(id) {

    let rs = await axios({
        url: URLS.ITEM + '/' + id
    });

    return rs;
}

我们在created生命周期下发送请求,vue的生命周期请参考小迪的blog参考

\app\src\views\Detail.vue

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

    export default {
        name: "Home",

        data() {
            return {
                items: []
            }
        },

        async created() {
            let id = this.$route.params.id;

            let rs = await apis.getItem(id);

            this.item = rs.data;
        },

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

http://localhost:8080/view/4

在这里插入图片描述

在这里插入图片描述

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

commit description:a1.81(example02-2——实现详情页请求)

tag:a1.81

以上就是动态路由,和react是一样思路,可能写法有些不同。



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值