详解Vue路由开启keep-alive时的注意点


Posted in Javascript onJune 20, 2017

这个不是业务的要求,但是看到每次进入页面就重新渲染DOM然后再获取数据更新DOM,觉得作为一个前端工程师有必要优化下的加载逻辑,正好vue提供了keep-alive的功能,所以就试用了下。当然,干任何事儿都不会一帆风顺的,在路上的磕磕碰碰在所难免,故在此记录下遇到的问题,希望看到这篇文章的人能有所帮助。ps:这个也没多难。

HTML部分:

<template>
 <div class="app">
  <keep-alive>
   <router-view></router-view>
  </keep-alive>
 </div>
</template>

JavaScript部分:

.....

  created: function () {
   console.log(1)
  },
  mounted: function () {
   console.log(2)
  },
  activated: function () {
   console.log(3)
  },
  deactivated: function () {
   console.log(4)
  }

.....

1. 什么阶段获取数据

页面生命周期钩子如上面的代码所示,这四个是最常用到的部分。这部分需要注意下,当引入keep-alive的时候,页面第一次进入,钩子的触发顺序created-> mounted-> activated,退出时触发deactivated。当再次进入(前进或者后退)时,只触发activated。

我们知道keep-alive之后页面模板第一次初始化解析变成HTML片段后,再次进入就不在重新解析而是读取内存中的数据,即,只有当数据变化时,才使用VirtualDOM进行diff更新。故,页面进入的数据获取应该在activated中也放一份。数据下载完毕手动操作DOM的部分也应该在activated中执行才会生效。

所以,应该activated中留一份数据获取的代码,或者不要created部分,直接将created中的代码转移到activated中。

2. $route中的数据读不到

以前的写法是在data中将需要的$route数据进行赋值,便于其余方法使用,但是使用了keep-alive后数据需要进入页面在activated中再次获取,才能达到更新的目的。定义一个initData方法,然后在activated中启动。

initData: function () {
    let _this = this;
    _this.fromLocation = JSON.parse(this.$route.query.fromLocation);
    _this.toLocation = JSON.parse(this.$route.query.toLocation);
    _this.activeIndex = parseInt(this.$route.params.activeIndex) || 0;
    _this.policyType = parseInt(this.$route.params.policyType) || 0;
   },

3. 当页动态修改url

需求描述:当页面在进行轮播操作的时候希望能记录当前显示的轮播ID(activeIndex)。当进入下一个页面再返回的时候能记住之前的选择,将轮播打到之前的ID位置。所以我想将这部分信息固化在url中,轮播发生变化时,修改URL。这样实现比较符最小修改原则,其余页面不用变动。

之前的写法是将activeIndex放在$route的query中,当轮播后,将activeIndex的值存入$route.query.activeIndex中,然后$router.replace当前路由,理论上应该能发生变化,但实际没有。

查看文档后说,$route是只读模式。当然,对象部分是他监管不到的,我修改了并不是正统的做法。

神奇的地方来了:当我将activeIndex记在params中,轮播变动修改params中的参数,然后$router.replace当前路由,却能发生对应的变化。代码如下:

let swiperInstance = new Swiper('#swiper', {
  pagination: '.swiper-pagination',
  paginationClickable: false,
  initialSlide: activeIndex,
  onSlideChangeEnd: function (swiper) {
    let _activeIndex = swiper.activeIndex;
    _this.$route.params.activeIndex = _activeIndex;
    // $router我放到了window上方便调用
    window.$router.replace({
      name: _this.$route.name,
      params: _this.$route.params,
      query: _this.$route.query
    });
    // 根据activeIndex,在这里初始化下面显示的数据
    _this.transferDetail = _this.allData.plans[_activeIndex].segments;
    _this.clearBusDetailFoldState();
  }
});

4. 事件如何处理

估计你也能猜到,发生的问题是事件绑定了很多次,比如上传点击input监听change事件,突然显示了多张相同图片的问题。

也就是说,DOM在编译后就缓存在内容中了,如果再次进入还再进行事件绑定初始化则就会发生这个问题。

解决办法:在mounted中绑定事件,因为这个只执行一次,并且DOM已准备好。如果插件绑定后还要再执行一下事件的handler函数的话,那就提取出来,放在activated中执行。比如:根据输入内容自动增长textarea的高度,这部分需要监听textarea的input和change事件,并且页面进入后还要再次执行一次handler函数,更新textarea高度(避免上次输入的影响)。

5. 地图组件处理

想必这是使用keep-alive最直接的性能表现。之前是进入地图页面后进行地图渲染+线路标记;现在是清除以前的线路标记绘制新的线路,性能优化可想而知!

我这里使用的是高德地图,在mounted中初始化map,代码示例如下:

export default {
  name: 'transferMap',
  data: function () {
    return {
      map: null,
    }
  },
  methods: {
    initData: function () {},
    searchTransfer: function (type) {},
    // 地图渲染 这个在transfer-map.html中使用
    renderTransferMap: function (transferMap) {}
  },
  mounted: function () {
    this.map = new AMap.Map("container", {
      showBuildingBlock: true,
      animateEnable: true,
      resizeEnable: true,
      zoom: 12 //地图显示的缩放级别
    });
  },
  activated: function () {
    let _this = this;
    _this.initData();
    // 设置title
    setDocumentTitle('换乘地图');
    _this.searchTransfer(_this.policyType).then(function (result) {
      // 数据加载完成
      // 换乘地图页面
      let transferMap = result.plans[_this.activeIndex];
      transferMap.origin = result.origin;
      transferMap.destination = result.destination;
      // 填数据
      _this.transferMap = transferMap;
      // 地图渲染
      _this.renderTransferMap(transferMap);
    });
  },
  deactivated: function () {
    // 清理地图之前的标记
    this.map.clearMap();
  },
}

6. document.title修改

这个不是keep-alive的问题,不过我也在这里分享下。

问题是,使用下面这段方法,可以修改Title,但是页面来回切换多次后就不生效了,我也不知道为啥,放到setTimeout中就直接不执行。

document.title = '页面名称';

下面是使用2种环境的修复方法:

纯js实现

function setDocumentTitle(title) {
  "use strict";
  //以下代码可以解决以上问题,不依赖jq
  setTimeout(function () {
    //利用iframe的onload事件刷新页面
    document.title = title;
    var iframe = document.createElement('iframe');
    iframe.src = '/favicon.ico'; // 必须
    iframe.style.visibility = 'hidden';
    iframe.style.width = '1px';
    iframe.style.height = '1px';
    iframe.onload = function () {
      setTimeout(function () {
        document.body.removeChild(iframe);
      }, 0);
    };
    document.body.appendChild(iframe);
  }, 0);
}

jQuery/Zepto实现

function setDocumentTitle(title) {
  //需要jQuery
  var $body = $('body');
  document.title = title;
  // hack在微信等webview中无法修改document.title的情况
  var $iframe = $('<iframe src="/favicon.ico"></iframe>');
  $iframe.on('load', function () {
    setTimeout(function () {
      $iframe.off('load').remove();
    }, 0);
  }).appendTo($body);
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Event altKey,ctrlKey,shiftKey属性解析
Dec 18 Javascript
在myeclipse中如何加入jquery代码提示功能
Jun 03 Javascript
JS设置网页图片vspace和hspace属性的方法
Apr 01 Javascript
js中利用tagname和id获取元素的方法
Jan 03 Javascript
JavaScript简单实现弹出拖拽窗口(一)
Jun 17 Javascript
js实现短信发送倒计时功能(正则验证)
Feb 10 Javascript
element 结合vue 在表单验证时有值却提示错误的解决办法
Jan 22 Javascript
微信小程序实现天气预报功能
Jul 18 Javascript
element ui table(表格)实现点击一行展开功能
Dec 04 Javascript
js序列化和反序列化的使用讲解
Jan 19 Javascript
layui添加动态菜单与选项卡
Jul 26 Javascript
使用vue编写h5公众号跳转小程序的实现代码
Nov 27 Vue.js
jquery基于layui实现二级联动下拉选择(省份城市选择)
Jun 20 #jQuery
详解Node.js access_token的获取、存储及更新
Jun 20 #Javascript
详解angular 中的自定义指令之详解API
Jun 20 #Javascript
JS移动端/H5同时选择多张图片上传并使用canvas压缩图片
Jun 20 #Javascript
BootStrap Select清除选中的状态恢复默认状态
Jun 20 #Javascript
Vue实现路由跳转和嵌套
Jun 20 #Javascript
Vue.2.0.5实现Class 与 Style 绑定的实例
Jun 20 #Javascript
You might like
一些PHP Coding Tips(php小技巧)[2011/04/02最后更新]
2011/05/02 PHP
php中选择什么接口(mysql、mysqli)访问mysql
2013/02/06 PHP
php calender(日历)二个版本代码示例(解决2038问题)
2013/12/24 PHP
WordPres对前端页面调试时的两个PHP函数使用小技巧
2015/12/22 PHP
ThinkPHP中html:list标签用法分析
2016/01/09 PHP
替换php字符串中的单引号为双引号的方法
2017/02/16 PHP
调试php程序的简单步骤
2019/10/04 PHP
javascript重复绑定事件造成的后果说明
2013/03/02 Javascript
浅谈重写window对象的方法
2014/12/29 Javascript
Underscore.js 1.3.3 中文注释翻译说明
2015/06/25 Javascript
jQuery+ajax实现实用的点赞插件代码
2016/07/06 Javascript
JavaScript代码模拟鼠标自动点击事件示例
2020/08/07 Javascript
vue form表单post请求结合Servlet实现文件上传功能
2021/01/22 Vue.js
[20:57]Ti4主赛事第三天开幕式
2014/07/21 DOTA
Python压缩解压缩zip文件及破解zip文件密码的方法
2015/11/04 Python
python实现批量按比例缩放图片效果
2018/03/30 Python
django缓存配置的几种方法详解
2018/07/16 Python
Python 2.7中文显示与处理方法
2018/07/16 Python
Python 变量类型详解
2018/10/10 Python
Python opencv相机标定实现原理及步骤详解
2020/04/09 Python
Python插件机制实现详解
2020/05/04 Python
K近邻法(KNN)相关知识总结以及如何用python实现
2021/01/28 Python
HTML5中的新元素介绍
2008/10/17 HTML / CSS
详解HTML5中表单验证的8种方法介绍
2016/12/19 HTML / CSS
林清轩官方网站:山茶花润肤油开创者
2016/10/26 全球购物
美国领先的礼品卡网站:GiftCards.com
2016/11/02 全球购物
以实惠的价格提供高品质的时尚:Newchic
2018/01/18 全球购物
Feelunique中文官网:欧洲最大化妆品零售电商
2020/07/10 全球购物
时尚休闲吧创业计划书
2014/01/25 职场文书
乐观自信演讲稿范文
2014/05/21 职场文书
单位委托书怎么写
2014/09/21 职场文书
个人优缺点总结
2015/02/28 职场文书
辞职信怎么写?你都知道吗?
2019/06/24 职场文书
MySQL表的增删改查基础教程
2021/04/07 MySQL
SSM项目使用拦截器实现登录验证功能
2022/01/22 Java/Android
Win11怎么跳过联网验机 ?Win11跳过联网验机激活教程
2022/04/05 数码科技