Vue routing

What is a SPA

SPA is short for Single Page application, which translates as single page application. Simply put, SPA is a Web project with only one HTML page. Once the page is loaded, SPA will not reload or jump the page due to the user’s operation. Instead, JS is used to transform the HTML content dynamically to simulate the jump between multiple views.

The emergence of front-end routing

With the emergence of AJAX technology, SPA gradually evolved, and the emergence of SPA has greatly improved the user experience. In user interaction, there is no need to refresh the page, and data is obtained asynchronously through AJAX technology, making the page presentation more smooth.

However, since the user interaction in SPA is realized by changing the HTML content with JS, the URL of the page itself does not change, which leads to two problems:

  • 1. SPA cannot record the user’s forward and backward operations
  • 2. In SPA, there will be a variety of pages to display, but only one pageURLIs not user friendly, you have to re-click the page you want to go to every time you refresh the page
  • 3, there is no unified concept of path-page, page management is complex, and it is not friendly to maintain

Front-end routing is used to solve the above problems, such as vue-router and react-router

Vue-router

Front-end routing is a path manager. Generally speaking, VUe-Router is a link path management system of WebApp. The single-page application of VUE is based on routing and components. Routing sets the access path, which corresponds to the URL of the page, and maps the path to the component. Traditional page applications use hyperlinks to switch and jump pages. In vue-Router, it is switching between paths, that is, switching between components. The essence of routing module is to establish the mapping relationship between URL and page, which is realized through URL when refreshing, advancing and retreating.

Why not use the A tag: Since vue is a single-page application that has only one main index.html, the A tag doesn’t work and you have to use vue-Router to manage it.

The principle of

Simply put, there is only one HTML page that matches a route (access path) for each component. Instead of updating the entire page when a user refreshes, forwards, backwards, or jumps, only one component is updated based on the route. To meet the above requirements, we meet the following two core requirements:

  • 1, change,urlInstead of letting the browser send a request to the server.
  • 2, can listen to the URL changes, and perform the corresponding operations (such as component switch)

There are two modes that do this: hash mode and History mode

Hash pattern

Vue-router uses hash mode by default: uses the characters following the # after the URL. For example www.baidu.com/#aaaa where #aaaa is the hash value we want. Why hash can be used:

  • 1.hashThe change in value does not cause the browser to send a request to the server and does not cause a page refresh.
  • 2,hashA change in value is triggeredhashchangeThe event
  • 3,hashValue changes are also recorded in the browser’s historybackButton to go back to the previous onehashvalue

Before the emergence of the HISTORY mode of H5, the hash mode was basically used to realize front-end routing

The history mode

Browsers had history objects before HTML5. But it can only be used for page hopping

  • history.go(n)// Forward or backward, n represents the number of pages, and a negative number represents backward
  • history.forward()// Move forward one page
  • history.back()// Go back one page

In HTML5, History has the following new API

  • history.pushState()// Add a new state to the history stack
  • history.replaceState()// Modify the current item in the history stack
  • history.state// Returns the current state object

PushState and replaceState both accept three parameters (state,title, URL)

  • state: a valid JS object that can be used in thepopstateIn the event
  • title: Most browsers ignore this parameter and can pass null placeholders
  • url: Any valid URL (must be the same as the current URL, otherwise an exception will be thrown) used to update the browser URL. In the callpushStateorreplaceStateA new history with the new URL is immediately generated (the current URL has become the most recent), but the browser does not load the URL immediately (the page is not refreshed) and may load the URL later in certain circumstances, such as when the user reopens the browser or presses enter in the address bar.

The difference between pushState and replaceState is that:

  • pushStateRecords with new urls are added to the history stack while the existing history is retained.
  • replaceStateWill place the current page in the history stackThe state, urlReplace with the latest

Because the pushState and replaceState methods can change the current URL without refreshing the page, they can be used to implement front-end routing.

However, since calls to pushState and replaceState do not trigger events (popState events are only triggered when the user manually clicks the forward or back buttons or calls the go, back, or forward methods in JS), there are two corresponding solutions:

  • 1. Click the forward and back buttons or in thejsIn the callGo, back, forwardMethod: ListenpopstateEvent in the event callback based on the currenturlRender the corresponding page.
  • 2, when the need to jump path (callpushMethod: first render the corresponding page according to the path, and then pass after the page rendering is completedpushStateorreplaceStateMethod to update the browser URL.

This implements front-end routing for history mode

After history changes the URL, the page will not refresh, but after we manually refresh the page, the browser will send a request to the server with the current URL, but because we only have one HTML file, the browser will process other paths, the situation will be 404. At this point, you need to add a candidate resource on the server that covers all cases: if the URL does not match the static resource, the HTML file of the single-page application is returned. This leaves it entirely up to the front end to handle the routing.

Select hash and history modes

Hash advantages:

  • 1, good compatibility, compatible with IE8
  • 2. Single-page applications can be processed without any configuration on the server

Disadvantages:

  • 1. The path is ugly
  • 2. The anchor point function will fail
  • 3. The samehashThe history stack is not updated

The history advantages:

  • 1. The path is better
  • 2, the anchor function is available
  • 3,pushStateYou can add the same record to the history stack

Disadvantages:

  • 1, poor compatibility, not compatible with IE9
  • 2. Server support is required

Vue – the use of the router

  • 1. Open CMD command NPM install vue-router to install the routing module of vUE

  • 2. Introduce vue.js first and then vue-router.js, because vue-router is based on VUE. Vue.use(plugin) installs VueRouter using the plugins provided by vue.js. The purpose of this is not to rely on the Vue version, the two versions can be used interchangeably. This plug-in mechanism works by calling the install method of the plug-in (if there is no install method, the passed plug-in is called as a function).

import Vue from 'vue'
import VueRouter from 'vue-router'
// Pass VueRouter as a plug-in: the purpose is not to rely on vue, you can mix versions, or you can just use VueRouter
Vue.use = function(plugin, options){
  plugin.install(this, options)
}
Vue.use(VueRouter) // The plugin's install method is called and the Vue is passed in
Copy the code

Install.js does the following:

  • 1, the introduction ofVueSave it for later use
  • 2. Inject the root component into each component, ensuring that eachVueCan get the Router attribute on the root component
  • 3, to achieve the route response type principle, the root component on the_routeProperties are defined as responsive data, such that_routeProperties change to update the view
  • 4. Initialize the route
  • 5. Register the global routing component
// install.js
import View from './components/view'
import Link from './components/link'

export let _Vue 

export function install(Vue){
  _Vue = Vue
  // The root component is injected into each component in the manner of mixins
  Vue.mixin({
    beforeCreate(){
      // The router attribute is the root component
      if(this.$options.router){
        this._routeRoot = this
        this._router = this.$options.router
        /* Init should be placed before defineReactive. History. current is the record of the route corresponding to the current URL. Then we just need to update the view */ by defining the reactive attribute _route on the root component pointing to the latest routing record
        this._router.init(this)
        Vue.utils.defineReactive(this.'_route'.this._router.history.current)
      } else {
        this._routeRoot = this.$parent && this.$parent._routeRoot || this}}})// Add a property broker to facilitate the use of property routing properties in components
  Object.defineProperty(Vue.property, '$route', {get(){
      return this._routeRoot._route
    }
  })
  Object.defineProperty(Vue.property, '$router', {get(){
      return this._routeRoot._router
    }
  })
  Vue.component('RouterView', View)
  Vue.component('RouterLink', Link)
}
Copy the code

Instantiation VueRouter

  • 1. Declare to create a routing table and associate paths with corresponding components in the routing table
  • 2. Create a route instance, initialize the route, and import the route to the routing table
  • 3. Register routes in vUE instances
import App from './App'
let Home = { template:'< div > home page < / div >' };
let List = { template:
      
List page
}; // create a route instance let router = new VueRouter({// Initialize the route: pass in the routing table mode: 'history'.// Back end support is required routes: [// First level path must be preceded by '/' { path: '/'.component:Home },// Routes displayed by default (default routes displayed do not need to add /) { path: '/home'.component:Home },// One path corresponds to one component { path: '/list'.component:List }, { path: The '*'.redirect:'/home' }// Redirects to the home component when the user enters a random path, preventing 404 from appearing ] / / es6 shorthand }); //2. Inject the routing instance into the vue root instance and then use it in the page new Vue({ el:'#app', router, // Inject routing (ES6 abbreviation) render: h= > h(App) }) Copy the code
// vue route SRC /index.js
export default class VueRouter {
  // The corresponding history instance will be generated based on the corresponding schema and mounted on the current class instance
  init(app){ // This is the instance of the root component passed in when router.init is called in install.js
    const history = this.history
    const setupListener = () = >{
      // It is convenient to add some other operations
      history.setupListener()
      // todo...
    }
    // Get the current path, call the transitionTo method, and match the path to the corresponding route.
    history.transitionTo(history.getCurrentLocation(), setupListener)
    history.listen(route= >{
    /* Because in install.js the _route attribute of the root (app) component is already defined for reactive vue.util.definereactive (this, '_route', This._router.history.current) so just update the data to drive the view update */
      app._route = route
    })
  }
}
Copy the code

router-view

Router-view (Global component: used to render routing components) Router-view is used as a global component in the page to render routing pages to the page

<div id="app">
  <router-view></router-view>
</div>
Copy the code

router-link

Use the router-link global component for click-to-jump

Router-link has two properties:

  • to: Which path to jump to (must be added, value is the path to jump to)
  • tag: want torouter-linkWhich label to change (default isaThe label)
	<! Modify the above HTML as follows -->
<div id="app">
  <router-link to="/home" tag="button">Home page</router-link>
  <router-link to="/list" tag="button">List of pp.</router-link>
  <! -- if you want params as an object and you want params as an object, you can only jump with name (ptah) -->
  <router-link :to="{name:'list',params:{userId:1}}" tag="button">List of pp.</router-link>
  <router-view></router-view>
</div>
Copy the code

Routing information and methods

After routing is registered in an instance of vue, each vue component instance can obtain the _router and _route attributes on the root component by obtaining the $router and $route attributes (because install.js was already proxy when vue. use was injected).

  • $route: Route information object, which represents the status information of the current active route, including the information about the current URL resolution and the records of the routes matched by the URL
  • $router: an instance of the current route, with various hop methods on the prototype

$router

  • this.$router.push(): Forcibly jumps to a path. The parameter is path
  • this.$router.replace(): Route replacement, replacing the current path with a new one (rarely used)
  • this.$router.go(): Returns a level. The parameter is how many levels to return (-1 is the upper level, 1 is the lower level)

$route

The currently active routing information object. This property is read-only, and the properties inside it are immutable, but it is possible to watch it.

  • $route.path: a character string corresponding to the path of the current route, which is always resolved to an absolute path, such as/foo/bar.
  • $route.paramsA:key/valueObject, containing dynamic fragments and fully matched fragments, is an empty object if there are no routing parameters.
  • $route.queryA:key/valueObject, representingURLQuery parameters. For example, for paths/foo? user=1, there are$route.query.user == 1, is an empty object if there are no query parameters.
  • $route.hash: indicates the current routehashValue (with#) if nothashValue is an empty string.
  • $route.fullPath: after parsingURLContains query parameters andhashThe full path to.
  • $route.name: Indicates the name of the current route, if any.
  • $route.redirectedFrom: If redirection exists, it is the name of the route from which the redirection originated.
// Since there are many paths and we cannot write them to death, we need to write them in a regular form to match paths
 /article/2/d // a path
 /article/:c/:a {c:2,a:d} $route.params {c:2,a:d}
Copy the code

Nesting of routes

Second-level routes can be nested in the routing table. The template of the first-level route that is nested with second-level routes needs to be modified accordingly.

<div id="app">
  <router-link to="/home">Home page</router-link>
  <router-link to="/detail">Details page</router-link>
  <router-view></router-view><! Level 1 Routing display area -->
</div>
<template id="detail">
  <div>
    <router-link to="/detail/info">Personal center</router-link>
    <router-link to="/detail/about">About me</router-link>
    <router-view></router-view><! -- Secondary route display area -->
  </div>
</template>
Copy the code
/ / component
let home={template:'<div>home</div>'};
let detail={template:'#detail'};
let info={template:'<div>info</div>'};
let about={template:'<div>about</div>'};
// Create a routing table
let routes=[
  { path:'/home'.component:home },
  {
    path:'/detail'.component:detail,
    // The secondary route is written in the childern attribute
    children: [// The path of level-2 or higher routes should never contain '/'. If the path contains'/', it indicates level-1 routes
      { path:'info'.component:info },
      { path:'about'.component:about }
    ]
  },
];
// Initializes the route and passes it to the routing table
let router = new VueRouter({ 
  mode: 'history',
  routes
});

let vm = new Vue({
  el:'#app'.// Register the route
  router
})
Copy the code

Dynamic routing

Methods to be used:

  • router.beforeEach:vue-routerThe provided navigational guard is mainly used to guard navigation by jumping or canceling. There are several opportunities for embedding route navigation: global, single route proprietary, or component level.
  • router.addRoutes(): Dynamic mount route (the function of this method is only in the path to see the corresponding page, but the menu display is required), the parameter must be a matchroutesAn array of options required

Next (‘/’) or next({path: ‘/’}): {path: ‘/’}): {path: ‘/’}): {path: ‘/’}); redirect to a different location. The current navigation will be aborted and a new one will be started.

In this way, we can easily avoid the previous problem by next(to). This line re-enters the route. beforeEach hook function and releases the hook with next() to ensure that all routes are mounted.

The router index. Js file

import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)

// Create a static routing table
export const constantRouterMap = [
  { path: '/ 404'.component: () = > import('@/views/404'), hidden: true },
  {
    path: '/'.component: Layout,
    redirect: '/home'.name: 'Home'.children: [{
      path: 'home'.component: () = > import('@/views/home/index'),
      meta: { title: 'home'.icon: 'home'}}}]]// Initialize the route to the static routing table and export it
export default new Router({
  mode: 'history'.// Use history mode
  scrollBehavior: () = > ({ y: 0 }),
  routes: constantRouterMap
})

// All routes (dynamic routing table that needs to be filtered, add items directly here later, filter table according to permissions after dragging permission)
export const asyncRouterMap = [
  // Permission management
  {
    path: '/access'.component: Layout,
    name: 'access'.children: [{path: 'index'.name: 'access/index'.component: () = > import('@/views/access/index'),
        meta: { title: 'Permission Management'.icon: 'lock'}}},// Operation background
  {
    path: '/operation'.component: Layout,
    name: 'operation'.meta: {
      title: 'Back office'.icon: 'operation'
    },
    children: [
      // Inke Live
      {
        path: 'live'.component: () = > import('@/views/operation/index'), // Parent router-view
        name: 'operation/live'.meta: { title: Inpidlive },
        children: [
          // Feedback
          {
            path: 'feedback'.name: 'operation/live/feedback'.component: () = > import('@/views/feedback/index'),
            meta: { title: 'Feedback'}}]}]Copy the code

After creating a route, you need to filter the global routing table after obtaining the permission to filter out useless routes.