文章目录
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: branch05commit 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: branch05commit description:a1.79(example01-2——设置过滤器)
tag:a1.79
3. 路由对象
vue-router 会在组件中添加(注入)两个属性
- $router:做与当前路由无关的操作,如跳转页面
- $route:与当前路由相关操作
3.1 $router 对象
该对象其实就是 new VueRouter(…) 得到的路由对象,通过该对象我们可以访问全局路由信息,调用路由下的方法,比如:go
、back
、push
等
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: branch05commit 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
对象。
实际在React
的router-dom
中也有这两个东西,$router
、$route
<=> history
、location
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: branch05commit description:a1.81(example02-2——实现详情页请求)
tag:a1.81
以上就是动态路由,和react
是一样思路,可能写法有些不同。
(后续待补充)