[转] 2017-11-20 发布 另辟蹊径:vue单页面,多路由,前进刷新,后退不刷新
目的:vue-cli构建的vue单页面应用,某些特定的页面,实现前进刷新,后退不刷新,类似app般的用户体验。
注: 此处的刷新特指当进入此页面时,触发ajax请求,向服务器获取数据。不刷新特指当进入此页面时,不触发ajax请求,而是使用之前缓存的数据,以便减少服务器请求,用户体验更流畅。
项目需求:
任何技术的探索,都来自项目的需求。之前经手的一个项目是微信端商城,使用的是传统的mvc模式,利用的是jq+js,因此对于商城的项目需求比较熟悉。目前在学习vue,练手一个商城,遇到之前经常提及而无法很好解决的需求。有些页面需要前进刷新,后退不刷新。比如,从商城的【首页】-->【详情页】-->【订单提交页】,每次打开新页面都需要获取新数据,但是按下返回键后,就不需要再获取新数据了,而滚动条还保留在之前的位置。最常见的操作是从【首页】-->【详情页】,然后在从【详情页】-->【首页】,如此反复。
实例如图:
前人经验:
前人栽树,后人好乘凉。技术圈的分享一直都在蓬勃发展。遇到问题,我们可以尽情去搜索,去寻找大佬的足迹。针对上述需求,看到一个分享vue-router 之 keep-alive,比较符合我的需求,但是使用到我的项目上发现,稍微有点不适合。此分享技术要点,比较适合两个页面之前的跳转,返回。而我的页面是多个路由(2+)之间的跳转,返回。无奈,只能去自己探索发现。不过此技术要点给了我很好的启发,特此感谢作者。@ RoamIn
实现思路:
注:demo中,index页面包含三个链接导航。page1-->page2-->page3.依次前进,每次前进到一个新页面都需要获取数据,而按下后退键后,从page3返回到page2,page2不再获取新数据,而是使用之前缓存的数据。从page2返回到page1时,page1不再获取新数据,而是使用之前的数据。所以,page1和page2需要缓存,page3不需要缓存。可以把page1想象成首页,page2想象成详情页,page3想象成订单提交页。这样方便理解。
利用keep-alive 缓存需要缓存的页面
在app.vue中改写router-view
<keep-alive>
<router-view v-if="$route.meta.keepAlive">
<!-- 这里是会被缓存的视图组件,比如 page1,page2 -->
</router-view>
</keep-alive> <router-view v-if="!$route.meta.keepAlive">
<!-- 这里是不被缓存的视图组件,比如 page3 -->
</router-view>在router/index.js中添加路由元信息,设置需要缓存的页面
routes: [{
path: '/',
name: 'index',
component: index,
meta: {
keepAlive: false, //此组件不需要被缓存
}
},
{
path: '/page1',
name: 'page1',
component: page1,
meta: {
keepAlive: true, //此组件需要被缓存 }
},
{
path: '/page2',
name: 'page2',
component: page2,
meta: {
keepAlive: true, // 此组件需要被缓存 }
},
{
path: '/page3',
name: 'page3',
component: page3,
meta: {
keepAlive: false, // 此组件不需要被缓存
}
}
]钩子函数的执行顺序
不使用keep-alive
beforeRouteEnter --> created --> mounted --> destroyed使用keep-alive
beforeRouteEnter --> created --> mounted --> activated --> deactivated
再次进入缓存的页面,只会触发beforeRouteEnter -->activated --> deactivated 。created和mounted不会再执行。我们可以利用不同的钩子函数,做不同的事。务必理解上述钩子函数的执行时机和执行顺序,本教程的核心就依赖于此钩子函数
activated和deactivated是使用keep-alive后,vue中比较重要的两个钩子函数,建议详细了解下。
需缓存的页面的写法
注:demo中的page1和page2,这两个页面都需要缓存,思路一样,以下以page1为例,page2不再赘述。
示例文件:components/page1.vuedata中初始化一个str字符串,存放从后台获取的数据
data() {
return {
msg: "我是第一个页面",
str: "" // 加载页面后执行获取数据的方法,插入到此
};
}methods中创建一个方法,模拟从后台获取数据
methods: {
getData() {
// getData方法,模拟从后台请求数据
this.str = "我是通过调用方法加载的数据。。。";
}
}修改router/index.js中的配置
每次进入页面,我们都需要知晓是从哪个页面进来的,用以判断是否需要获取数据。以这个page1页面为例,当我们知晓是从page2过来的,我们就可以认为是用户操作了返回键,这时page1页面就不需要再获取新数据了,使用之前缓存的数据就可以了。如果是从别的页面过来的,我们就需要获取数据。
我们可以通过beforeRouteEnter这个钩子函数中的from参数判断是从哪个页面过来的,这个参数执行时,组件实例还没创建,所有不能在data中定义变量。我们可以在路由中定义一个变量,用来判断。
在router/index.js的meta中添加isBack变量,默认false
{
path: '/page1',
name: 'page1',
component: page1,
meta: {
keepAlive: true, //此组件需要被缓存
isBack:false, //用于判断上一个页面是哪个
}
},
{
path: '/page2',
name: 'page2',
component: page2,
meta: {
keepAlive: true, // 此组件需要被缓存
isBack:false, //用于判断上一个页面是哪个
}
},beforeRouteEnter中判断是从哪个页面过来的
判断是从哪个路由过来的,如果是page2过来的,表明当前页面不需要刷新获取新数据,直接用之前缓存的数据即可
beforeRouteEnter(to, from, next) {
// 路由导航钩子,此时还不能获取组件实例 `this`,所以无法在data中定义变量(利用vm除外)
// 参考 https://router.vuejs.org/zh-cn/advanced/navigation-guards.html
// 所以,利用路由元信息中的meta字段设置变量,方便在各个位置获取。这就是为什么在meta中定义isBack
// 参考 https://router.vuejs.org/zh-cn/advanced/meta.html
if(from.name=='page2'){
to.meta.isBack=true;
//判断是从哪个路由过来的,
//如果是page2过来的,表明当前页面不需要刷新获取新数据,直接用之前缓存的数据即可
} next();
},activated中执行getData这个获取数据的方法
因为这个页面需要缓存。只有第一次进入时才会执行created和mounted方法,再次进入就不执行了。而activated每次进入都执行,所以在这个钩子函数中获取数据。
activated() {
if(!this.$route.meta.isBack){
// 如果isBack是false,表明需要获取新数据,否则就不再请求,直接使用缓存的数据
this.getData();
}
// 恢复成默认的false,避免isBack一直是true,导致下次无法获取数据
this.$route.meta.isBack=false },
这样就可以了?
当这样设置完毕后,你执行起来,貌似是可以了。第一次进入page1,能获取新数据,从page2返回时,不再获取新数据了,而是使用之前缓存的数据。但这样还有一个问题,当用户从page1进入page2后,因为某种原因,手动刷新了page2的页面。这时再返回到page1,发现之前缓存的数据丢失了,而且也没有再重新获取。所以我们还需要再添加一个判断条件,当用户手动刷新页面后,再返回时就需要重新获取数据了。
如何添加这个条件,判断用户是否刷新了页面呢?我们知道,当使用keep-alive后,只有第一次进入后会触发created钩子函数,再次进入就不再执行了。当用户刷新了页面,这个钩子函数就会又执行,所以,我们可以利用这个小技巧来做点文章。
data中定义变量isFirstEnter用来判断是否第一次进入,或是否刷新了页面,默认false
data() {
return {
msg: "我是第一个页面",
str: "", // 加载页面后执行获取数据的方法,插入到此
isFirstEnter:false // 是否第一次进入,默认false
};
},created中把isFirstEnter变为true,说明是第一次进入或刷新了页面
created() {
this.isFirstEnter=true;
// 只有第一次进入或者刷新页面后才会执行此钩子函数
// 使用keep-alive后(2+次)进入不会再执行此钩子函数
},activated中增加判断条件
activated() {
if(!this.$route.meta.isBack || this.isFirstEnter){
// 如果isBack是false,表明需要获取新数据,否则就不再请求,直接使用缓存的数据
// 如果isFirstEnter是true,表明是第一次进入此页面或用户刷新了页面,需获取新数据
this.str=''// 把数据清空,可以稍微避免让用户看到之前缓存的数据
this.getData();
}
// 恢复成默认的false,避免isBack一直是true,导致下次无法获取数据
this.$route.meta.isBack=false
// 恢复成默认的false,避免isBack一直是true,导致每次都获取新数据
this.isFirstEnter=false; },这样应该就可以了
不需要缓存页面的写法
注:demo中的page3,这个页面不需要缓存,该怎么写就怎么写,不需要做特别的设置。
其它设置:
使用keep-alive后,可能有点小问题:第二个页面可能继承第一个页面的滚动条的高度。(在我项目中遇到的)
比如:page1向下滚动后,再进入page2,这时page2的滚动条可能是之前的高度,可能不会在顶部。
解决方法一
每次离开记录滚动条的高度,再次进入时根据项目需要再恢复之前的高度,或者置顶。解决方法二(推荐)
router/index.js中添加如下代码(如不理解,请看参考链接)
参考:HTML5 History 模式 滚动行为mode: 'history',
scrollBehavior(to, from, savedPosition) {
if (savedPosition) {
return savedPosition
} else {
return {
x: 0,
y: 0
}
}
}
疑问点:
在此次demo练习中,打印了一下钩子函数的执行顺序,发现一个疑问点(我对钩子函数理解也很浅显):
从page1进入page2时,先执行了page2的beforeRouteEnter和created方法,然后才执行page1的deactivated方法。
所以我把这两个初始化设置,放在了activated里面,而没有放在deactivated中
this.$route.meta.isBack=false;
this.isFirstEnter=false;
[转] 2017-11-20 发布 另辟蹊径:vue单页面,多路由,前进刷新,后退不刷新的更多相关文章
- 另辟蹊径:vue单页面,多路由,前进刷新,后退不刷新
目的:vue-cli构建的vue单页面应用,某些特定的页面,实现前进刷新,后退不刷新,类似app般的用户体验.注: 此处的刷新特指当进入此页面时,触发ajax请求,向服务器获取数据.不刷新特指当进入此 ...
- vue单页应用前进刷新后退不刷新方案探讨
引言 前端webapp应用为了追求类似于native模式的细致体验,总是在不断的在向native的体验靠拢:比如本文即将要说到的功能,native由于是多页应用,新页面可以启用一个的新的webview ...
- 关于处理移动端Vue单页面及其内嵌兼容问题
关于处理移动端Vue单页面及其内嵌兼容问题 question:由于最近转移了以前的H5项目,重构使用Vue单页面,导致部分手机内嵌或在微信浏览器中无法浏览,或者无法使用ajax请求:手机机型千变万化, ...
- 处理 Vue 单页面应用 SEO 的另一种思路
vue-meta-info 官方地址: monkeyWangs/vue-meta-info (设置vue 单页面meta info信息,如果需要单页面SEO,可以和 prerender-spa-plu ...
- Vue单页面骨架屏实践
github 地址: VV-UI/VV-UI 演示地址: vv-ui 文档地址:skeleton 关于骨架屏介绍 骨架屏的作用主要是在网络请求较慢时,提供基础占位,当数据加载完成,恢复数据展示.这样给 ...
- vue单页面打包文件大?首次加载慢?按需加载?是你打开方式不对
部署各vue项目,走了一遍坑.... vue单页面应用刷新404 找到nginx多网站配置文件:类似nginx/sites-available/www.baidu.com server { liste ...
- [one day one question] Vue单页面应用如何保证F5强刷不清空数据
问题描述: Vue单页面用按F5强刷,数据就恢复初始了,这怎么破? 解决方案: store.subscribe((mutation, state) => { sessionStorage.set ...
- vue单页面处理SEO问题
设置vue 单页面meta info信息 vue-meta-info,(https://github.com/muwoo/vue-meta-info)如果需要单页面SEO,可以和 prerender- ...
- Vue单页面应用阻止浏览器记住密码
Vue单页面应用阻止浏览器记住密码 ——IT唐伯虎 摘要: Vue单页面应用阻止浏览器记住密码. 现象1:路由切换时再次提示“是否记住密码” 登录页面有个密码输入框,输入账号密码进行登录: 登录完成后 ...
随机推荐
- Linux-系统调用理解
系统调用即为Linux内核中设置的一组用于实现各种系统功能的子程序,操作系统通过系统调用为运行在其上的进程提供服务. 由于进程一般不能访问内核所占内存空间以及调用内核函数,为了与用户态进程进行交互,内 ...
- org.apache.catalina.core.StandardContext.startInternal Context [/test] startup failed due to previou
解决方法: WEB-INF/classes目录下新建一个文件叫logging.properties,截图如下: 代码如下: handlers=org.apache.juli.FileHandler,j ...
- 大数据-hadoop生态之-HDFS
一.HDFS初识 hdfs的概念: HDFS,它是一个文件系统,用于存储文件,通过目录树定位文件,其次,他是分布式的,由很多服务器联合起来 实现功能,集群中的服务器各有各自的角色 HDFS设计适合一次 ...
- MongoDB用户权限认证
关于用户的认证及权限 用户是跟着库创建的,在哪个库创建的什么权限的什么用户,只对此库有相应权限(除超级管理员以外). 官网文档:https://docs.mongodb.com/master/refe ...
- JSON使用与类型转换
JSON语法与对象 JSON方法与使用 一.JSON语法与对象 JSON是英文JavaScript Object Notation(JavaScript 对象表示法)的缩写,是存储和交换文本信息的语法 ...
- 2018-2019-2 《Java程序设计》第7周学习总结
20175319 2018-2019-2 <Java程序设计>第7周学习总结 教材学习内容总结 本周学习<Java程序设计>第8章: 1.String类: Java专门提供了用 ...
- ubuntu18系统美化
1. 将选定的背景图片 login-bg.jpg 移动到 /usr/share/backgrounds/ 目录下 sudo mv currentdir/mypicture.jpg /usr/share ...
- 微信小程序button组件样式
点击微信按键组件才能出授权,所以自定义样式就是必须的了,来自网友的帮助,如下图 <button class='btn1' open-type='contact'> <image cl ...
- APPLE-SA-2019-3-27-1 watchOS 5.2
APPLE-SA-2019-3-27-1 watchOS 5.2 watchOS 5.2 is now available and addresses the following: CFStringA ...
- centos 7.2 下 nginx 1.14.1 安装部署
Nginx1.14.1安装部署 1.环境: 所有源码在跳板机kx的/web/soft下 2.安装依赖: [root@bogon src]# yum install -y libxml2 openssl ...