聊聊Vue 中 title 的动态修改问题
由于之前的Vue项目打包成果物一直是嵌入集成平台中,所以一直没有关注过项目的title。直到最近,突然有个需求,要求点击按钮在集成平台外新开一个页面,此时我才发现,原来我的项目的title一直是万年不变的vue-project。理所应当的,这个问题被测试爸爸提了一个大大的缺陷。
犯了错的我赶紧解决这个问题,但是经过一段时间的摸索,我却发现,这一个小小的问题,却有着很多不同的解法。
首先,毫无疑问的是,我们应该使用document.title方法通过DOM操作来修改title的值。此时,距离解决问题还差两步:
1.如何传递title?
2.何时修改title?
ps:很多人提到过在微信或者一部分IOSwebview(下文一律以微信指代)中无法通过document.title方法修改title的值,这个问题的解决方案在文末的彩蛋中会提及。
title的传递
接下来进入第一个重点:title的传递。根据传递title值的方式,分为两种方案:
1.全局变量传递
2.路由传递
何为全局变量传递?全局变量传递指的是所有页面维护同一个全局变量,切换页面对其重新赋值,最常见的方法是使用Vuex,当然,如果你要使用this.$root甚至丧心病狂地想要使用provide/inject一样可以达到类似的效果。
路由传递的方法就比较容易理解了,即通过路由跳转传参传递title的值。由于业务逻辑中本身就包含大量的路由传参,为了解耦方便后续维护,推荐将title的值通过路由配置中的meta进行传递。
之后,通过访问当前路由对象($route)的meta属性即可获取到title值。
//router.js constroutes=[ { 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 constdefaultTitle='默认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(){ //插件安装钩子 functioninstall(Vue){ varsetWechatTitle=function(title,img){ if(title===undefined||window.document.title===title){ return } //修改title document.title=title varmobile=navigator.userAgent.toLowerCase() //兼容性判断 if(/iphone|ipad|ipod/.test(mobile)){ //创建空的iframe,触发onload事件 variframe=document.createElement('iframe') iframe.style.display='none' //替换成站标favicon路径或者任意存在的较小的图片即可 iframe.setAttribute('src',img||'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7') //onload回调函数 variframeCallback=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(typeofexports==='object'){ module.exports=install }elseif(typeofdefine==='function'&&define.amd){ define([],function(){ returninstall }) }elseif(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的动态修改问题,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!