聊聊Vue 中 title 的动态修改问题


Posted in Javascript onJune 11, 2019

 由于之前的 Vue 项目打包成果物一直是嵌入集成平台中,所以一直没有关注过项目的 title。直到最近,突然有个需求,要求点击按钮在集成平台外新开一个页面,此时我才发现,原来我的项目的 title 一直是万年不变的 vue-project。理所应当的,这个问题被测试爸爸提了一个大大的缺陷。

犯了错的我赶紧解决这个问题,但是经过一段时间的摸索,我却发现,这一个小小的问题,却有着很多不同的解法。

首先,毫无疑问的是,我们应该使用 document.title 方法通过 DOM 操作来修改 title 的值。此时,距离解决问题还差两步:

1.如何传递 title?
2.何时修改 title?

ps:很多人提到过在微信或者一部分 IOS webview (下文一律以微信指代)中无法通过 document.title 方法修改 title 的值,这个问题的解决方案在文末的彩蛋中会提及。

title 的传递

接下来进入第一个重点:title 的传递。根据传递 title 值的方式,分为两种方案:

1.全局变量传递
2.路由传递

何为全局变量传递?全局变量传递指的是所有页面维护同一个全局变量,切换页面对其重新赋值,最常见的方法是使用 Vuex,当然,如果你要使用 this.$root 甚至丧心病狂地想要使用 provide/inject 一样可以达到类似的效果。

路由传递的方法就比较容易理解了,即通过路由跳转传参传递 title 的值。由于业务逻辑中本身就包含大量的路由传参,为了解耦方便后续维护,推荐将 title 的值通过路由配置中的 meta 进行传递。

之后,通过访问当前路由对象($route)的 meta 属性即可获取到 title 值。

// router.js
const routes = [
 {
  path: '/',
  ...
  meta: {
   title: '首页'
  }
 }, {
  path: '/A',
  meta: {
   title: 'A模块'
  }
 }
]
// 业务模块,获取 title
...
beforeCreate () {
 console.log(this.$route.meta)
}
...

通过上面的两种方法,可以顺利传递 title 的值。

title 的修改时机

完成了 title 值的传递,接下来我们谈谈何时该修改 title。

想到这个问题,大多数人第一个想到的应该就是在生命周期钩子中修改 title。

生命周期钩子

一般情况下,我们在 mounted 生命周期钩子中进行初始化请求,所以惯性思维之下,我在 mounted 中进行了 title 的修改。

// 业务代码
mounted () {
 document.title = this.$route.meta.title
}

结果,效果不佳,标签页的 title 延迟 1 秒以上才成功修改。通过这个延迟可以发现,显然,我们的代码执行地太晚了!

回忆了一下 Vue 源码中初始化相关的代码细节,我们可以发现,我们甚至在 beforeCreate 钩子中就可以进行 title 的修改。

改动后的代码如下:

// 业务代码
beforeCreate () {
 document.title = this.$route.meta.title
}

可以发现,修改后的代码效果明显好了许多,延迟感虽然还有,但是已经不太明显。

路由守卫

比起在生命周期钩子中修改 title 值,在路由跳转时利用路由守卫完成 title 的修改,岂不美哉?毕竟路由跳转发生在生命周期函数执行之前,使用路由守卫修改 title 值可以明显降低 title 修改的延时。

// router.js
router.beforeEach((to, from, next) => {
 document.title = to.meta.title
 next()
})

此时,我们基本完美完成了功能需求,但是,还是有一点小瑕疵——如果 meta 中没有定义 title 值,此时 title 值就变成了 undefined,扑街~

所以,我们需要设置默认的 title 值(一般可以是该项目的名称),作为 title 值不存在时的备胎。修改后的代码如下:

// router.js
const defaultTitle = '默认 title'
router.beforeEach((to, from, next) => {
 document.title = to.meta.title ? to.meta.title : defaultTitle
 next()
})

到这里为止,我们完美实现了需求,并且实现了该功能与业务代码的解耦。

彩蛋1:使用 vue-meta 管理 title

vue-meta 插件在安装时,像 Vuex 类似,注入了全局状态——metaInfo,你可以通过定义 metaInfo 对象中的 title 属性,实现 title 的动态修改。

彩蛋2:vue-wechat-title 源码解析

在搜索相关资料的时候,vue-wechat-title 这个包的出现频率出乎意料的高,这个包主要解决了前面提到的那个问题:在微信中无法通过 document.title 方法修改 title 的值。当然,这个兼容性问题都能解决了,正常情况下的 title 修改当然不在话下。

我们先来看看 vue-wechat-title 的源码:

// vue-wechat-title 源码
(function () {
 // 插件安装钩子
 function install (Vue) {
  var setWechatTitle = function (title, img) {
   if (title === undefined || window.document.title === title) {
    return
   }
   // 修改 title
   document.title = title
   var mobile = navigator.userAgent.toLowerCase()
   // 兼容性判断
   if (/iphone|ipad|ipod/.test(mobile)) {
    // 创建空的 iframe,触发 onload 事件
    var iframe = document.createElement('iframe')
    iframe.style.display = 'none'
    // 替换成站标favicon路径或者任意存在的较小的图片即可
    iframe.setAttribute('src', img || 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7')
    // onload 回调函数
    var iframeCallback = function () {
     setTimeout(function () {
      // 卸磨杀驴
      iframe.removeEventListener('load', iframeCallback)
      document.body.removeChild(iframe)
     }, 0)
    }
    // 定义事件
    iframe.addEventListener('load', iframeCallback)
    document.body.appendChild(iframe)
   }
  }
  // 定义全局指令,
  Vue.directive('wechat-title', function (el, binding) {
   // update 钩子,调用 title 修改函数
   setWechatTitle(binding.value, el.getAttribute('img-set') || null)
  })
 }

 if (typeof exports === 'object') {
  module.exports = install
 } else if (typeof define === 'function' && define.amd) {
  define([], function () {
   return install
  })
 } else if (window.Vue) {
  Vue.use(install)
 }
})()

由于微信浏览器只在onload 事件中通过 title 的值初始化标题,而后续的 title 修改,无法触发标题的修改。既然 onload 事件能够通过 title 修改标题,那么我创建一个空的 iframe 触发 onload 事件修改了标题后就移除它。这种方式根据 title 修改了标题,并且没有对页面造成额外的影响。

众所周知,vue-wechat-title 通过 v-wechat-title 指令来触发 title 的动态修改,每当指令的值修改后,触发 update 钩子中的回调函数——setWechatTitle。该函数通过前面提到的兼容性处理,实现了document.title 对标题的修改。

总结

以上所述是小编给大家介绍的Vue 中 title 的动态修改问题,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

Javascript 相关文章推荐
JXTree对象,读取外部xml文件数据,生成树的函数
Apr 02 Javascript
Jquery.TreeView结合ASP.Net和数据库生成菜单导航条
Aug 27 Javascript
基于datagrid框架的查询
Apr 08 Javascript
php+js实现倒计时功能
Jun 02 Javascript
使用jQuery将多条数据插入模态框的实现代码
Oct 08 Javascript
javascript常用方法汇总
Dec 02 Javascript
javascript实现日期格式转换
Dec 16 Javascript
Jquery实现动态切换图片的方法
May 18 Javascript
jquery实现列表上下移动功能
Feb 25 Javascript
AngularJS  双向数据绑定详解简单实例
Oct 20 Javascript
EL表达式截取字符串的函数说明
Sep 22 Javascript
JS数据类型STRING使用实例解析
Dec 18 Javascript
vue+element模态框中新增模态框和删除功能
Jun 11 #Javascript
vue.js中导出Excel表格的案例分析
Jun 11 #Javascript
ES6 Proxy实现Vue的变化检测问题
Jun 11 #Javascript
webpack实践之DLLPlugin 和 DLLReferencePlugin的使用教程
Jun 10 #Javascript
vue2 中二级路由高亮问题及配置方法
Jun 10 #Javascript
JS中实现一个下载进度条及播放进度条的代码
Jun 10 #Javascript
vuex 中插件的编写案例解析
Jun 10 #Javascript
You might like
PHP的FTP学习(二)[转自奥索]
2006/10/09 PHP
PHP下用rmdir实现删除目录的三种方法小结
2008/04/20 PHP
php 分库分表hash算法
2009/11/12 PHP
PHP print类函数使用总结
2010/06/25 PHP
仿Aspnetpager的一个PHP分页类代码 附源码下载
2012/10/08 PHP
php文件类型MIME对照表(比较全)
2016/10/07 PHP
用jscript实现列出安装的软件列表
2007/06/18 Javascript
JQuery 获得绝对,相对位置的坐标方法
2010/02/09 Javascript
不使用中间变量,交换int型的 a, b两个变量的值。
2010/10/29 Javascript
JavaScript动态添加列的方法
2015/03/25 Javascript
基于jquery实现导航菜单高亮显示(两种方法)
2015/08/23 Javascript
JavaScript对HTML DOM使用EventListener进行操作
2015/10/21 Javascript
jQuery设置下拉框显示与隐藏效果的方法分析
2019/09/15 jQuery
layui table复选框禁止某几条勾选的实例
2019/09/20 Javascript
JS代码检查工具ESLint介绍与使用方法
2020/02/04 Javascript
vue-cli打包后本地运行dist文件中的index.html操作
2020/08/12 Javascript
[37:02]OG vs INfamous 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/17 DOTA
Python写的英文字符大小写转换代码示例
2015/03/06 Python
Django项目中用JS实现加载子页面并传值的方法
2018/05/28 Python
python 简单照相机调用系统摄像头实现方法 pygame
2018/08/03 Python
Python 实现取矩阵的部分列,保存为一个新的矩阵方法
2018/11/14 Python
Python进程间通信Queue消息队列用法分析
2019/05/22 Python
通过实例解析Python调用json模块
2019/12/11 Python
利用Python代码实现一键抠背景功能
2019/12/29 Python
python实现用类读取文件数据并计算矩形面积
2020/01/18 Python
Python 字符串处理特殊空格\xc2\xa0\t\n Non-breaking space
2020/02/23 Python
Django 返回json数据的实现示例
2020/03/05 Python
python zip,lambda,map函数代码实例
2020/04/04 Python
HTML5 Canvas的性能提高技巧经验分享
2013/07/02 HTML / CSS
学校司机岗位职责
2013/11/14 职场文书
完美的中文自荐信
2014/05/24 职场文书
优秀三好学生事迹材料
2014/08/31 职场文书
MySQL的全局锁和表级锁的具体使用
2021/08/23 MySQL
Java中CyclicBarrier和CountDownLatch的用法与区别
2021/08/23 Java/Android
用Python仅20行代码编写一个简单的端口扫描器
2022/04/08 Python
Win11 Beta 22621.601 和 22622.601今日发布 KB5017384修复内容汇总
2022/09/23 数码科技