关于对vue-router的优化(详尽版)
致爱丽丝 人气:2这两天总结了关于vue-router优化的几点技法,做个笔记
在基于vue的移动端app中,通过vue-router可以便捷的进入某一路由或回退到上一路由,但是若不对vue-router做相关优化处理,则会造成以下几个问题:
1.切换路由时,频繁向后台发送请求
2.切换路由时,页面会卡顿,影响用户体验
基于这些困扰,我们从头开始探究vue-router
问题1:切换路由时,频繁向后台发送请求,以及解决办法
在常规的路由配置下,我们使用App.vue作为app根组件:
app.vue有一个router-view标签用于显示内部组件,
而在router/index.js中,path为'/'的根路由映射了home,这代表home组件作为App.vue的子组件
因而,App.vue下的router-view代表了身为子组件的home.vue,而home组件作为App.vue的子组件(路由),本身又是除app.vue以外所有后代路由的根路由。
它们一起构成了整个APP路由系统。这是vue-router的常规描述。
萌新们往往会将所有的路由一股脑的与根路由配置在同一级,但事实证明,这是不可取的。
假设我们F12键,打开netWork -> XHR 时就会发现,
在home路由下,进入某个路由,然后回退到上个路由时,我们请求了2次数据,即点击了要进入的路由时,请求了一次;回退到上个路由时,又请求了一次
而这与我们的期待是不一样的:每当我们点击一个新路由时,vue才向后台发送网络请求,而我们回退到某个路由时(比如本例,我们回退到home路由上),
则回退到的路由在没有刷新事件前不要请求数据。
所以原因就在于此:
与根路由同级时,每次进入或回退某个路由,上一个已请求到的路由资源都被销毁了,因而每当进入一个路由地址(无论是回退上一路由还是进入某一新路由),
app.vue都会重新加载一次router-view,vue都会向服务器发起一次网络请求,造成服务器实则没必要的花销。
并且随着用户不断进入或者回退某个路由,耗费的花销会越来越可观
那么,保持组件的状态,便是解决的方法:
-
解决方法一:使用vue内置组件keep-alive保持组件状态
使用keep-alive标签包裹app.vue里router-view标签,这样就相当于包裹了包括home在内的所有路由组件:
<template>
//App.vue
<div id="app">
<keep-alive>
<router-view/>
</keep-alive>
</div>
</template>
当我们打开f12再次尝试进入或者回退到某个标签时,发现只有在进入一个新路由地址时,才会发起请求, keep-alive可以缓存router-view的内容,
这样似乎已经达到了我们的期望,
但正是keep-alive的缓存特性有一个致命的缺陷———— keep-alive也会缓存动态路由的状态。
尝试举个例子来解释这句话:
假设用户进入了一个商品界面,但用户对这个商品并不满意,当用户回退到上一级而进入了一个中意的商品界面却发现,
跟刚刚那个界面一样,且无论进入哪个商品界面都跟第一个商品界面一样时,
这便会是keep-alive的弊端----keep-alive标签会缓存动态路由的状态,因而不会再进行数据请求,
这对动态路由来说是致命的
所以,这个方法是不可取的
- 解决办法二:更改router的配置
将home下所有子路由放置在home路由的children路由里,将子路由的子路由放置在子路由的children里,以此类推,即:
//router/index.js
{
path: '/',
name: 'Home',
component: Home,
// 根目录的子路由,优化路由,防止每次回退或进入都会加载
//home路由的子路由放置在自身的children路由下
children: [
{
path : '/playListView',
name:'PlayListView',
component:() => import(/* webpackChunkName: "about" */ '../views/playListView.vue'),
children:[
//子路由的子路由放置在自己的children下,以此类推
{
path : ':id',//传入id值,指明是哪一个playlist
name:'PlayListViewInfo',
component:() => import('../views/playListInfo.vue')
}
]
}
]
}
如果某一后代路由是动态路由,直接给该后代路由加动态路由参数,不加父路由的path
如果使用了该方法,则还需要给home下每一个后代路由添加router-view标签,用以标识该路由是home根路由的后代路由
举个栗子:
<template>
<!-- 歌单视图 歌单详情页-->
<div class="page">
<div>
<m-header>
全部歌单
</m-header>
<div class="play-wrapper">
<play-list :data="playListData" @clickItem = 'gotoPlayListInfo '></play-list>
</div>
</div>
<router-view/> <!-- 该路由组件上的router-view标签标识它的子路由-->
</div>
</template>
ps: 如果点击路由后有报错: Navigating to current location ("/router") is not allowed ,请点击这里
这样设置后,会出现点击无法进入路由的结果。
但是如果打开f12会看到DOM中存在有该后代路由的dom,且点击后,地址栏上已经显示了子组件的路由,但用户界面上依然只显示了home组件,
也就是说当点击了子路由以后,子路由显示了,但父路由依旧存在于当前界面,阻碍了用户的视图
这与我们期待的有所不同: 点击某个子路由,然后给用户展现该路由的内容,但其实已经接近明朗————仅仅是页面上有了父路由界面与子路由界面并存的现象
解决办法:(提高后代组件的层级,使后代组件可以覆盖父组件) 在home的所有后代路由的根div上添加一个叫page的class:
/* app的公共样式common.js */
.page{
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background:#f3f4f9 ; /*与html背景色保持一致*/
z-index: 9999; /*使用最高层级,覆盖home组件的层级*/
overflow: scroll;/*在移动端中使滚动可用*/
}
而以上操作完成后,就可以发现,点击进入路由时,会发送一个网络请求,而回退到上一路由时,则不会发起请求,且页面正常显示;且就算进入了一个动态路由也可以正常显示
这样,就解决了切换路由时,频繁向后台发送请求的问题。
问题2: 进入某一路由或回退到上一路由时,页面会有生硬的进入显示现象,影响用户体验
原因: 路由间的切换没有添加过渡效果
基于问题一,我们可以使用vue的transition标签包裹组件的router-view标签,使用transition的name属性来定制过渡样式:
举个栗子:
<template>
<div class="page">
<div>
<m-header >全部歌手</m-header>
<artist-list :data="artistsData"
@clickItem="gotoArtistsInfo"
class="artist"></artist-list>
</div>
<transition name="slide"><!--
加载全部内容
- 猜你喜欢
- 用户评论