introduce

Vue Router is the official route manager of vue.js. Its deep integration with vue.js core makes building single-page applications a breeze. The features included are:

  • Nested routing/view chart

  • Modular, component-based routing configuration

  • Route parameters, queries, and wildcards

  • View transition effect based on vue. js transition system

  • Fine-grained navigation control

  • Links with automatically activated CSS classes

  • HTML5 historical mode or Hash mode is automatically degraded in IE9

  • Custom scroll bar behavior

start

Creating a single page application with Vue. Js + Vue Router is very simple. With vue.js, we can already compose applications by combining components. When you add a Vue Router, what we need to do is map components to routes and tell the Vue Router where to render them

The installation

npm i vue-router -S

In the main. In js

import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
Copy the code

Recommended use: Vue add Router add-on (remember to submit in advance)

The basic use

router.js

import Vue from 'vue'
/ / 1. Imported
import Router from 'vue-router'
import Home from './views/Home.vue'
import About from './views/About.vue'
//2. Modularity mechanism uses Router
Vue.use(Router)
//3. Create router objects
const router = new Router({
  //mode: 'history', //history mode clean page address does not have #/ such symbols exist
  routes: [{path: '/home'.component: Home
  },
  {
    path: '/about'.component: About
 }]
})
export default router;
Copy the code

main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false
new Vue({
    // 4. Mount root instance
    router,
    render: h= > h(App)
}).$mount('#app')
Copy the code

After the above configuration is complete

<template>
  <div id="app">
    <div id="nav">
	<! -- Use router-link to navigate -->
	<! -- Pass the to attribute to specify the connection -->
	<! -- Router-link is rendered as an A tag by default -->
	<router-link to="/">Home</router-link> |
        <router-link to="/about">About</router-link> |
	<! -- Route exit -->
        <! -- Routing matching components will be rendered here -->
	<router-view/>
    </div>
  </div>
</template> 
Copy the code

Open your browser and switch between the Home and About hyperlinks to see the effect

After routing

When configuring a route, add a name to the route so that access can be dynamically performed based on the name

const router = new Router({
        routes: [{path: '/home'.name: 'home'.component: Home
 	},
 	{
            path: '/about'.name:'about'
            component: About
 	}]
})
Copy the code

To link to a named route, pass an object to router-link’s to property:

<router-link :to="{name:'home'}">Home</router-link> |
<router-link :to="{name:'about'}">About</router-link> |
Copy the code

Dynamic Route Matching

We often need to map all the routes that a pattern matches to the same component. For example, we have a User component that is used to render for all users with different ids. We can use dynamic segments on vue-Router routes to achieve this effect

User.vue

<template> 
  <div> 
  	<h3>The user page</h3>
	</div>
</template>
<script>
export default{};</script>
<style lang="scss" scoped>
</style>
Copy the code

The routing configuration

const router = new Router({
    routes: [{path: '/user/:id'.name: 'user'.component: User,
    }]
})
Copy the code
<router-link :to="{name:'user',params{id:1}}">User</router-link> |
Copy the code

See the effect

When a route is matched, the parameter value is set to this.$route.params, which can be used in each component, so we can update the User template to print the current User ID:

<template>
  <div> 
  	<h3>{{$route.params.id}}</h3>
	</div>
</template>
Copy the code

Responds to changes in routing parameters

As a reminder, when routing parameters are used, such as navigating from /user/1 to /user/2, the original component instance is reused. Because both routes render the same component, reuse is more efficient than destroying and recreating. However, this also means that the component’s lifecycle hooks are no longer called.

To respond to changes in routing parameters when reusing components, you can simply watch the $route object:

$route object watch: {$route(to, from) {console.log(to.params.id); }}, * /
// Or use the navigation guard
beforeRouteUpdate(to,from,next){
    // View route changes
    // Next must be called, otherwise route changes will be blocked
    next();
}
Copy the code

404 routing

const router = new Router({
    routes: [//....
	// If no route is matched, the 404 page is displayed
 	{
            path: The '*'.component: () = > import('@/views/404')}]})Copy the code

When using wildcard routes, ensure that the order of routes is correct, that is, routes containing wildcards should be placed last. The route {path: ‘*’} is usually used for client 404 errors

When a wildcard is used, $route.params automatically adds a parameter named pathMatch. It contains parts of the URL that are matched by wildcards:

{
  path: '/user-*'.component: () = > import('@/views/User-admin.vue')}this.$route.params.pathMatch // 'admin'
Copy the code

Matching priority

Sometimes, the same path can match multiple routes. In this case, the priority of the matched routes is the highest according to the route definition order: the one defined first has the highest priority.

Query parameters

Like address that appear on this: http://localhost:8080/page? id=1&title=foo

const router = new Router({
    routes: [/ /...
        {
            path: '/page'.name: 'name'.component:() = > ('@/views/Page.vue')}]})Copy the code
<router-link :to="{name: 'page', query:{id: 1, title: 'foo'}}">User</router-link>
Copy the code

Go to http://localhost:8080/page? Id = 1 & title = foo view the Page

Page.vue

<template>
	<div>
		<h3>Page Page</h3>
		<h3>{{$route.query.userId}}</h3>
	</div>
</template>
<script>
export default {
    created () {
	// View the routing information object
	console.log(this.$route); }},</script>
<style>
</style>
Copy the code

Route redirection and alias

redirect

Example redirects from/to /home:

const router = new Router({
    mode: 'history'.routes: [
        / / redirection
     {
        path: '/'.redirect: '/home'
     },
     {
        path: '/home'.name: 'home'.component: Home
     },
   ]
})
Copy the code

The redirection target can also be a named route:

const router = new VueRouter({
    routes: [{path:'/'.redirect: {name: 'name'}}}])Copy the code

The alias

{
    path: 'user/:id'.name: 'user'.component: User,
    alias: '/alias'
}
Copy the code

The “alias” feature gives you the freedom to map UI structures to arbitrary urls, rather than being constrained by configuration nested structures.

Route component parameters are transmitted

Using $route in a component makes it highly coupled to its corresponding route, limiting its flexibility by limiting its use to certain urls.

Decouple components and routes using props:

Replace coupling with $route

Index.js

{
    path: '/user/:id'.name: 'user'.component: User,
    //props: true
    //props can also be a function
    props: (route) = > {
        id: route.params.id,
        title: route.query.title
    }
}
Copy the code

User.vue

<template>
  <div>
  	<h3>{{$route.params.id}}</h3>
		<h3>User page {{id}}</h3>
	</div>
</template>
<script>
export default{
    //....
    props: {
        id: {
            type: String.default: ' '}},}</script>
Copy the code

Props can also be a function

User.vue

<template>
  <div>
  	<h3>{{id}}-{{title}}</h3>
  </div>
</template>
<script>
export default {
    // ...
    props: {
	id: {
            type: String.default: ' '
 	},
	title: {type: String}}};</script>
Copy the code

Programmatic navigation

In addition to using

to create a tag to define navigation links, we can also use the router instance method. By writing code.

Note: Inside the Vue instance, you can pass
r o u t e r Access the routing instance. So you can call t h i s . Router Accesses the routing instance. So you can call this.
The router. Push.

declarative programmatic
<router-link :to="..." > router.push(...)

The argument to this method can be a string path or an object describing the address. Such as:

/ / string
this.$router.push('home')
/ / object
this.$router.push({path: 'home'})
// Named route
this.$router.push({name: 'user'.params: {userId}: '123'})
// With query parameters, change to /register? plan=private
this.$push({path: 'register'.query: {plan: 'private'}})
Copy the code

Move back

// Further forward in the browser record, equivalent to history.forward()
router.go(1)
// Step back to record, equivalent to history.back()
router.go(-1)
// Forward 3 steps record
router.go(3)
// If the history is insufficient, the default is failure
router.go(-100)
router.go(100)
Copy the code

Embedded routines by

/user/1/profile 			 	/user/1/posts +------------------+ +-----------------+ | User | | User | | +--------------+ | | +-------------+ | | | Profile |  | +------------> | | Posts | | || || || || | +--------------+ | | +-------------+ | +------------------+ +-----------------+Copy the code

router.js

{
    path: '/user/:id'.name: 'user'.component: User,
    props: ({params,query}) = >({
        id: params.id,
        title:query.title
    }),
    children: [// If /user/:id/profile matches successfully,
        // The Profile will be rendered in the User's 
      
        {	
            path:"profile".component: Profile
        },
        // if /user/:id/posts matched successfully,
        // Posts will be rendered in User's 
      
 	{
            path: "posts".component: Posts
 	}
   ]
}
Copy the code

Add a

to the User component template:

<template>
    <div>
        <h3>{{$route.params.id}}</h3>
        <h3>User page {{id}}</h3>
        <router-view></router-view>
    </div>
</template>
Copy the code

App.vue

<template>
    <div id='app'>
        <! -- Nested routine by -->
        <router-link to="/user/1/profile">User/profile</router-link> |
        <router-link to="/user/1/posts">User/posts</router-link> |
    </div>
</template>
Copy the code

Named view

Named views come in handy when you want to show multiple views at the same time (sibling) instead of nesting them, such as creating a layout that has sidebar (side navigation) and main (main content) views.

{
  path: '/home'.name: 'home'.// Note that this key is components
  components: {
    default: Home, // The default name
    main: () = >import('@/views/Main.vue'),
    sidebar: () = >import('@/views/Sidebar.vue')}}Copy the code

App.vue

<router-view/>
<router-view name='main'/>
<router-view name='sidebar'/>
Copy the code

Navigation guard

Navigation indicates that the route is changing.

Complete navigation parsing process

  1. Navigation is triggered.

  2. Call the leave guard in the inactivated component.

  3. Call the global beforeEach guard

  4. Call the beforeRouterUpdate guard (2.2+) in the reused component.

  5. Call beforeEnter in routing configuration.

  6. Parse the asynchronous routing component.

  7. Call beforeRouterEnter in the active component.

  8. Call the global beforeResolve guard (2.5+).

  9. Navigation confirmed.

  10. Call the global afterEach hook.

  11. Trigger a DOM update.

  12. Call the callback function passed to Next in the beforeRouterEnter guard with the created instance.

Global guard

You can register a global front-guard using router.beforeEach

const router = newVueRouter({... }) router.beforeEach((to, form, next) = > {
	/ /...
})
Copy the code

There is a demand, the user access in browsing the site, will visit many components, when the user to jump to/notes, found that the user is not logged in, should allow the user to log in to view at this time, should allow the user to jump to the login page, login to finish before he can see the contents of my notes, at this time of global guard has played a key role.

There are two routes /notes and /login.

router.vue

const router = new VueRouter({
    routes: [{path: '/notes'.name: 'notes'.component: () = > import('@/views/Notes')}, {path: '/login'.name: 'login'.component: () = > import('@/views/Login')]}})// Global guard
router.beforeEach((to, from, next) = > {
  // The user is accessing '/notes'
  if(to.path === '/notes') {
    // Check whether the user has saved the login status information
    let user = 
    JSON.parse(localStorage.getItem('user'))
    if(user) {
      // If yes, go ahead
      next();
    }else {
      // If no, go to the login page to log in
      next('/login')}}else{ next(); }})Copy the code

Login.vue

<template>
  <div>
     <input type="text" v-model="username">
     <input type="password" v-model="pwd">
     <button @click="handleLogin">submit</button>
  </div>
</template>
<script>
export default {
	data() {
    return {
      username: "".pwd: ""
    };
  },
  methods: {
    handleLogin() {
      //1. Obtain the user name and password
      //2. Interact with the backend
      setTimeout(() = > {
        let data = {
          username: this.username
        };
        // Save the user login information
        localStorage.setItem("user".JSON.stringfy(data));
        // Jump to my notes page
        this.$router.push({name: "notes"});
      }, 1000); }}},</script>
Copy the code

App.vue

<! -- Global Guard demo --><router-link to="/notes">My notes</router-link> |
<router-link to="/login">The login</router-link> |
<button @click="handleLogout">exit</button> 
<script>
export default {
    methods: {
        handleLogout() {
            // Delete login status information
            localStorage.removeItem("user");
            // Jump to the home page
            this.$router.push('/')}}}</script>
Copy the code
Guards within components

You can define the following route navigators directly within the routing component:

  • beforeRouteEnter
  • beforeRouteUpdate(2.2 Added)
  • beforeRouteLeave
<template>
  <div>
      <h3>User edit page</h3>
      <textarea name id cols="30" rows="10" v-model="content"</textarea>
      <button @click="saveData">save</button>
      <div class="wrap" v-for="(item, index) in list" :key="index">
          <p>{{item.title}}</p>
      </div>
  </div>
</template>
<script>
export default {
    data() {
        return {
          content: "".list: [].}},methods: {
        saveData() {
          this.list.push({
          title: this.content
        });
        this.content = ""; }},beforeRouteLeave(to, from, next) {
    // called when navigating away from the component's corresponding route
    // Access component instance 'this'
    if(this.content) {
      alert("Please make sure the information is saved before leaving.");
      next(false);
    }else{ next(); }}};</script>
Copy the code
The permission control of routing meta information is realized

Set a META field for the route to which you want to add permissions

{
    path: '/blog'.name: 'blog'.component:() = > import('@/views/Blog'),
    meta: {
        requiresAuth: true} {},// Route exclusive guard
    path: 'notes'.name: 'notes'.component: () = > import('@/views/Notes'),
    meta: {
        requiresAuth: true}},Copy the code
// Global guard
router.beforeEach((to, from, next) = > {
  if(to.matched.some(record= > record.meta.requiresAuth)) {
    // Permissions are required
    if(!localStorage.getItem('user')) {
      next({
        path: '/login'.query: {
          redirect: to.fullPath
        }
      })
    }else{ next(); }}else{ next(); }})Copy the code

Login.vue

// Login operation
handleLogin() {
    // 1. Obtain the user name and password
    // 2. Interact with the backend
    setTimeout(() = > {
        let data = {
            username: this.username
         };
	localStorage.setItem("user".JSON.stringify(data));
	// Jump to the previous page
	this.$router.push({path:this.$route.query.redirect });
    },1000};
}
Copy the code
Data acquisition

Sometimes, after entering a route, you need to fetch data from the server. For example, when rendering user information, you need to fetch user data from the server. We can do this in two ways:

  • Retrieves after navigation: Completes navigation, then retrieves data in the following component lifecycle hooks. Display instructions such as “loading” during data retrieval.

  • Before the completion of navigation: Before the completion of navigation, data is obtained from the guard entering the route, and navigation is performed after the data is obtained successfully.

Get the data after navigation is complete

When you use this approach, we immediately navigate and render the component, and then get the data in the component’s Created hook. This gives us the opportunity to show one loading state during data fetching and different loading states between different views.

<template>
  <div class="post"> 
    <div v-if="loading" class="loading">Loading...</div>
	<div v-if="error" class="error">{{ error }}</div> 
	<div v-if="post" class="content">
            <h2>{{ post.title }}</h2> 
            <p>{{ post.body }}</p>
	</div>
    </div>
</template>
Copy the code
<script>
export default {
    name: "Post".data() {
            return {
		loading: false.post: null.error: null
            };
 	},
	// Get data after component is created.
	// Data is already monitored
	created() {
	// If the route changes, the method is executed again
	this.fetchData();
 	},
	watch: {
    $route: "fetchData"
  },
  methods: {
    fetchData() {
      this.error = this.post = null;
      this.loading = true;
      this.$http.get('/api/post').then((result) = > {
        this.loading = false;
        this.post = result.data;
      }).catch((err) = > {
        this.error = err.toString();
      });
   }
}
</script>
Copy the code

Expanded content:

Multi-page application MPA each page is an.HTML file

A single page application SPA is equivalent to an A TAB that switches between different views