文章目录
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
我们可以通过路由对象 $route 的 query 属性来获取 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: branch05commit 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: branch05commit 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: branch05commit 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: branch05commit 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: branch05commit 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: branch05commit description:a1.87(example02-3——实现排序切换-代码优化)
tag:a1.87
(后续待补充)