聊聊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 相关文章推荐
JavaScript中通过闭包解决只能取得包含函数中任何变量最后一个值的问题
Aug 12 Javascript
jquery图形密码实现方法
Mar 11 Javascript
jQuery+jRange实现滑动选取数值范围特效
Mar 14 Javascript
30分钟快速掌握Bootstrap框架
May 24 Javascript
微信小程序开发实战教程之手势解锁
Nov 18 Javascript
bootstrap Table插件使用demo
Aug 07 Javascript
angularjs路由传值$routeParams详解
Sep 05 Javascript
详解js删除数组中的指定元素
Oct 31 Javascript
JavaScript私有变量实例详解
Jan 24 Javascript
基于VUE实现判断设备是PC还是移动端
Jul 03 Javascript
antd的select下拉框因为数据量太大造成卡顿的解决方式
Oct 31 Javascript
在VUE中使用lodash的debounce和throttle操作
Nov 09 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
在PWS上安装PHP4.0正式版
2006/10/09 PHP
PHP获取网址的顶级域名函数代码
2012/09/24 PHP
PHP中Session引起的脚本阻塞问题解决办法
2014/04/08 PHP
JS 文字符串转换unicode编码函数
2009/05/30 Javascript
Javascript 面向对象(一)(共有方法,私有方法,特权方法)
2012/05/23 Javascript
jQuery中json对象的复制方式介绍(数组及对象)
2013/06/08 Javascript
12种不宜使用的Javascript语法整理
2013/11/04 Javascript
javascript自动恢复文本框点击清除后的默认文本
2016/01/12 Javascript
JS导出PDF插件的方法(支持中文、图片使用路径)
2016/07/12 Javascript
jQueryUI 拖放排序遇到滚动条时有可能无法执行排序的小bug及解决方案
2016/12/19 Javascript
js实现手机拍照上传功能
2017/01/17 Javascript
vue数据双向绑定的注意点
2017/06/23 Javascript
详解Vue学习笔记入门篇之组件的内容分发(slot)
2017/07/17 Javascript
Node.js利用console输出日志文件的方法示例
2018/04/27 Javascript
js console.log打印对象时属性缺失的解决方法
2019/05/23 Javascript
JS实现时间校验的代码
2020/05/25 Javascript
三步搞定:Vue.js调用Android原生操作
2020/09/07 Javascript
原生js实现滑块区间组件
2021/01/20 Javascript
Python 用户登录验证的小例子
2013/03/06 Python
Python全排列操作实例分析
2018/07/24 Python
Python 从一个文件中调用另一个文件的类方法
2019/01/10 Python
Python小进度条显示代码
2019/03/05 Python
不归路系列:Python入门之旅-一定要注意缩进!!!(推荐)
2019/04/16 Python
Django文件存储 自己定制存储系统解析
2019/08/02 Python
python3 Scrapy爬虫框架ip代理配置的方法
2020/01/17 Python
Python如何使用队列方式实现多线程爬虫
2020/05/12 Python
Jacadi Paris英国官网:法国童装品牌
2019/08/09 全球购物
建筑工程技术应届生自荐信
2013/09/27 职场文书
《姥姥的剪纸》教学反思
2014/02/25 职场文书
公务员中国梦演讲稿
2014/08/19 职场文书
检查机关党的群众路线个人整改措施
2014/10/04 职场文书
新员工考核评语
2014/12/31 职场文书
安全员岗位职责
2015/02/10 职场文书
2016年国培研修日志
2015/11/13 职场文书
vue backtop组件的实现完整代码
2021/04/07 Vue.js
MySQL 用 limit 为什么会影响性能
2021/09/15 MySQL