Since the previous Vue project packaging results have been embedded in the integration platform, the title of the project has not been paid attention to. Until recently, there was a sudden demand to click the button to open a new page outside the integration platform. At that time, I found that the title of my project had been vue-project for thousands of years. Of course, this question was raised by the test dad with a big flaw.

I made a mistake to solve this problem, but after a period of groping, I found that this small problem, but there are many different solutions.

First, of course, we should use the document.title method to modify the title value through DOM manipulation. At this point, we are two steps away from solving the problem:

  1. How do I pass title?
  2. When do I change the title?

Ps: Many people have mentioned that it is impossible to modify the title value in wechat or some IOS WebView through the document.title method. The solution to this problem will be mentioned in the Easter egg at the end of this article.

The title of the pass

Next comes the first point: the passing of the title. According to the way of transmitting the title value, there are two schemes:

  1. Global variable passing
  2. Routing relay

What is global variable passing? Global variable pass means that all pages maintain the same global variable, and the most common way to reassign it is to use Vuex when switching pages. Of course, if you want to use this.$root, you can even use provide/inject to achieve similar effects.

The method of routing is easier to understand, that is, the value of title is passed through the route jump parameter. Since the service logic itself contains a large number of route transmission parameters, it is recommended that the title value be transmitted through the meta in the route configuration for the convenience of decoupling and subsequent maintenance.

The title value can then be obtained by accessing the meta attribute of the current route object ($route).

// router.js
const routes = [
  {
    path: '/'. meta: {title: 'home'}}, {path: '/A'.meta: {
      title: 'A module'}}]Copy the code
// Business module, get title. beforeCreate () {console.log(this.$route.meta)
}
...
Copy the code

With the above two methods, the title value can be passed smoothly.

When the title is modified

With the title value passed, let’s talk about when to change the title.

When most people think about this, the first thing that comes to mind is to change the title in the lifecycle hook.

Lifecycle hook

Normally, we initialize the request in mounted lifecycle hooks, so I changed the title in Mounted.

// Business code
mounted () {
  document.title = this.$route.meta.title
}
Copy the code

As a result, the title of the TAB page was delayed by more than 1 second before it was successfully modified. As you can see from this delay, it is clear that our code is executing too late!

Recalling the initialization details of the Vue source code, we can see that we can change the title even in the beforeCreate hook.

The modified code is as follows:

// Business code
beforeCreate () {
  document.title = this.$route.meta.title
}
Copy the code

It can be found that the modified code effect is much better, although there is still a sense of delay, but has not been too obvious.

Routing guard

Wouldn’t it be nice to use a route guard to change the title value on a route hop rather than in a lifecycle hook? After all, the route jump occurs before the lifecycle function is executed. Modifying the title value with the route guard can significantly reduce the delay of title modification.

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

At this point, we have almost completed the functional requirements, but there is a slight flaw — if the title value is not defined in the meta, the title value will become undefined

Therefore, we need to set the default title value (usually the name of the project) as a backup if the title value does not exist. The modified code is as follows:

// router.js
const defaultTitle = 'the default title'
router.beforeEach((to, from, next) = > {
  document.title = to.meta.title ? to.meta.title : defaultTitle
  next()
})
Copy the code

So far, we have perfectly implemented the requirements and decoupled the functionality from the business code.

Egg 1: Use vue-meta to manage titles

Vue-meta inserts a global state, metaInfo, like Vuex. You can change the title dynamically by defining the title attribute in the metaInfo object.

Easter egg 2: vue-weike-title source code analysis

When searching for relevant information, the frequency of vue-Weike-title package is unexpectedly high. This package mainly solves the problem mentioned above: the title value cannot be modified through the document.title method in wechat. Of course, this compatibility problem can be solved, under normal circumstances, of course, the title modification is not a problem.

Let’s look at vue-weike-title source code:

/ / the vue - wechat - the title the source code
(function () {
  // The plugin installs the hook
  function install (Vue) {
    var setWechatTitle = function (title, img) {
      if (title === undefined || window.document.title === title) {
        return
      }
      / / modify the title
      document.title = title
      var mobile = navigator.userAgent.toLowerCase()
      // Check compatibility
      if (/iphone|ipad|ipod/.test(mobile)) {
        // Create an empty iframe that triggers the onload event
        var iframe = document.createElement('iframe')
        iframe.style.display = 'none'
        // Replace it with the favicon path or any smaller image that exists
        iframe.setAttribute('src', img || 'data:image/gif; base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7')
        // onload callback function
        var iframeCallback = function () {
          setTimeout(function () {
            //
            iframe.removeEventListener('load', iframeCallback)
            document.body.removeChild(iframe)
          }, 0)}// Define events
        iframe.addEventListener('load', iframeCallback)
        document.body.appendChild(iframe)
      }
    }
    // Define the global directive,
    Vue.directive('wechat-title'.function (el, binding) {
      // Update the hook and call the title function to modify it
      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)
  }
})()
Copy the code

Since wechat browser only initializes the title through the value of title in the onload event, subsequent title changes cannot trigger the modification of the title. Since the onLoad event can change the title by title, I create an empty iframe that triggers the onLoad event to remove the title after it changes it. This changes the title based on the title without any additional impact on the page.

Vue-weike-title as we all know, vue-weike-title triggers dynamic title changes through the V-weike-title directive. Whenever the value of the directive is changed, the update hook callback function — setWechatTitle is triggered. This function modifies the title of document.title through the compatibility processing mentioned earlier.