This is the 5th day of my participation in the August More Text Challenge


series

  • Vue 3 basis
  • Vue 3 dynamic effect
  • Vue 3 components
  • Modular API
  • Vue Router Next
  • Vuex 4

We already have components for our application with vue.js, and when adding the Vue Router, all we need to do is map the (view) components to the route (URL), let the Vue Router know where to render them, and achieve the effect of multi-page switching in a single page application.

💡 Vue Router Next is Vue Router V4.x, which ADAPTS to Vue 3. Most of the API is retained, but some of the changes are not compatible with Vue Router V3. Please refer to the official documentation for migrating Vue Router V3. This article introduces the basic usage of Vue Router Next, focusing on the differences between 🎉 and Vue Router V3.

Install the introduction

The latest version of the VueRouter can be imported through the CDN. This module exposes the VueRouter object and creates a routing instance by calling its method createRouter at 🎉

<script src="https://unpkg.com/vue-router@4"></script>
Copy the code

💡 can also specify the version

<script src="https://unpkg.com/[email protected]/dist/vue-router.global.js"></script>
Copy the code

Use (router) to install the plugin (app is the Vue application instance, router is the routing instance). This supports routing throughout the application (no need to import routes in other subcomponents)

npm install vue-router@4
Copy the code
import { createApp } from 'vue';
import { createRouter } from 'vue-router';

const app = Vue.createApp({})
// Route configuration
const routes = [...]
const router = VueRouter.createRouter({
  // Use hash mode
  history: VueRouter.createWebHashHistory(),
  routes, // Route configuration
})
// The entire application supports routing
app.use(router)
Copy the code

Initialize the

🎉 Use the createRouter() method to create a route instance and configure the mapping between components and routes

import { createApp } from 'vue';
import VueRouter from 'vue-router';

// Route configuration
// Mapping rules for routes and components. Generally, each route path corresponds to a component
const routes = [
  { 
    // Route url (url)
    path: '/'.// Corresponding component (view)
    component: Home
  },
  { path: '/about'.component: About },
]

// Create router instance,
const router = VueRouter.createRouter({
  // Use hash mode
  history: VueRouter.createWebHashHistory(),
  // Configure the incoming route
  routes,
})

// Create and mount the root instance
// Use the router option to inject routes so that the entire application can use the routing function
createApp({}).use(router).mount('#app');
Copy the code

After the route is injected by calling app.use(Router), two concepts are commonly used in applications (where this represents the component instance) :

  • routerRouter, which is provided by the Vue Router plug-in with various methods of controlling routing within any componentthis.$routerAccess router
  • routeIt is an object that contains the current routing information and can passthis.$routeAccessing the current Route

💡 if 🎉 is in the option setup function, useRouter() accesses the route instance, and useRoute() accesses the current route

Finally, don’t forget to use the built-in

component of the Vue Router in the template of the Vue instance (component) so that the components matching the current route can be rendered on the page.

You can use the built-in < router-Link > component of the Vue Router to add a navigation UI component to the page, which is rendered as a tag by default

<div id="app">
  <div>
    <! -- Use router-link for navigation -->
    <! -- Specify links by passing 'to' -->
    <! - ` < the router - the link > ` will present with a correct ` href ` attribute ` < a > ` tags - >
    <router-link to="/">Go to Home</router-link>
    <router-link to="/about">Go to About</router-link>
  </div>

  <! -- Routing matching components will be rendered here -->
  <router-view></router-view>
</div>
Copy the code

Historical pattern

The argument passed to the method vuerouter.createrOuter ({}) is an object, and the mode attribute is discarded in VueRoute Next. You need to explicitly use the 🎉 history attribute to set what history mode the project uses

Hash pattern

🎉 is created with createWebHashHistory()

import { createRouter, createWebHashHistory } from 'vue-router'

const router = createRouter({
  history: createWebHashHistory(),
  routes: [
    / /...],})Copy the code

The actual URL passed inside the project in this mode is preceded by a hash character #, and since this part of the URL is never sent to the server, it does not require any special processing at the server level and does not cause page reloads. But it does have a bad effect on SEO.

HTML 5 mode

🎉 is created by createWebHistory() and requires a backend server

import { createRouter, createWebHistory } from 'vue-router'

const router = createRouter({
  history: createWebHistory(),
  routes: [
    / /...],})Copy the code

When using this history mode, the URL looks the same as the “normal” path, but at the same time you need to add a fallback route to the server so that the URL doesn’t match any static resources and it also serves up the same page as the index.html in your application. Examples of server configuration for Vue Router in HTML5 mode can be found in the official documentation.

The routing configuration

The argument passed to the method VueRouter. CreateRouter ({}) is an object in which the routes attribute is an array, each element representing a route and containing configuration information

const router = createRouter({
  history: createWebHistory(),
  routes: [{path: '/user/:username'.component: User
    }
  ],
})
Copy the code

The most basic route consists of the path and the corresponding view component

Routing meta information

When defining routing rules, you can set the option meta meta information and pass an object to store information about the route in the form of key-value pairs. This is equivalent to adding some additional information to the route besides the path. These additional information can be used in the route guard. For example, the navigation guard determines whether the access path needs login authentication based on meta information.

// Route configuration
const routes = [
  {
    path: '/posts'.component: PostsLayout,
    children: [{path: 'new'.component: PostsNew,
        // Only authenticated users can create posts
        meta: { requiresAuth: true}}, {path: ':id'.component: PostsDetail
        // Anyone can read the article
        meta: { requiresAuth: false}}]}]Copy the code

For the example above, if you want to determine whether authorization validation is required based on the meta information of the route, you can use intra-component guards

💡 a route can match multiple routes (all the matched route records will be exposed as $route.matched array, generally need to check the attributes of the feature by going through the elements of the number group), Vue Router provides us a $route.meta object, It is a non-recursive object that merges all meta fields (from parent field to child field), making it easier to access the meta information of the route.

router.beforeEach((to, from) = > {
  // Determine whether the current navigation requires authorization authentication based on the 'meta' information of the route
  // The default is to check the META object in each route record by traversing the to.matched array
  // to.matched.some(record => record.meta.requiresAuth)
  // This can now be checked directly from the to.meta object that all meta information is merged into
  if(to.meta.requiresAuth && ! auth.isLoggedIn()) {// If the route requires authorization, check whether you have logged in
    // If not, redirect to the login page
    return {
      path: '/login'.// Save our location so we can come back later
      query: { redirect: to.fullPath },
    }
  }
})
Copy the code

💡 If you write code in TypeScript, you can extend the RouteMeta interface to enter meta fields

// typings.d.ts or router.ts
import 'vue-router'

declare module 'vue-router' {
  interface RouteMeta {
    // This is optionalisAdmin? : boolean// Each route must be declared
    requiresAuth: boolean
  }
}
Copy the code

Page scrolling

When creating a route instance, you can set how to scroll when switching pages with the option scrollBehavior.

This option is a method in which the first two arguments receive to and from routing objects and the third argument savedPosition records the current page position. Returns either a ScrollToOptions location object (which tells the browser how to scroll the page) or a savedPosition (which tells the browser to scroll the page to the previous position)

const router = new VueRouter({
  routes: [...]. , scrollBehavior (to,from, savedPosition) {
    if (savedPosition) {
      // Navigate through the previous/Next buttons
      // The page is saved by savedPosition
      return savedPosition
    } else {
      // If there is no location record, the default is scroll to the top of the page
      return{ left: 0.top: 0}}}})Copy the code

Object information that returns the scroll position can be in a variety of formats:

  • 🎉 scroll to the specified axis return {left: number, top: number}, generally for all route navigation, simply scroll to the top of the page return {left: 0, top: 0}

  • 🎉 specifies an element (via CSS selectors or by passing a DOM directly) in the return object via the attribute EL, so that the scrolling displacement is relative to that element

    const router = createRouter({
      scrollBehavior(to, from, savedPosition) {
        // Always scroll 10px above the element #main
        return {
          // Pass a CSS selector or a DOM element via el
          el: '#main'.// You can also write it this way
          // el: document.getElementById('main'),
          top: -10,}}})Copy the code
  • Scroll to the specified anchor point

    const router = createRouter({
      scrollBehavior(to, from, savedPosition) {
        if (to.hash) {
          return {
            el: to.hash,
          }
        }
      },
    })
    Copy the code
  • Return savedPosition This value is available if and only if triggered by the browser’s forward/Back buttons (popState navigation)

  • Returns a falsy value or an empty object without scrolling

💡 can also enable the native smooth scrolling effect by adding the Behavior option to the returned object and setting the value to smooth

// ...
scrollBehavior (to, from, savedPosition) {
  if (to.hash) {
    return {
      el: to.hash,
      behavior: 'smooth',}}}Copy the code

💡 This method supports returning a Promise and resolving an object to indicate the expected location so that asynchronous/delayed scrolling can be done by waiting before the page scrolls. In this way, the scrolling behavior and page transitions can be better matched to achieve more elegant dynamic effects.

const router = createRouter({
  scrollBehavior (to, from, savedPosition) {
    return new Promise((resolve, reject) = > {
      setTimeout(() = > {
        resolve({ left: 0.top: 0})},500) // Wait 500ms for the page to scroll})}})Copy the code

After routing

When configuring a route, you can set a name (unique name) for a route. In this way, the name can be used to refer to the route with a long path for navigation. If the route is a dynamic route, the name is used together with the route parameters.

// Routing rules
const routes = [
  {
    path: '/user/:username'.name: 'user'
    component: User
  },
]
Copy the code

Declarative navigation, using route names and passing route parameters, the Vue Router concatenates corresponding urls

<router-link :to="{ name: 'user', params: { username: 'ben' }}">
  User
</router-link>
Copy the code

Programmatic navigation

router.push({ name: 'user'.params: { username: 'ben'}})Copy the code

Both navigation paths point to /user/ Ben

The alias

You can use the alias option to set an alias for the route when configuring the route. This function allows you to map the same UI structure to any URL, instead of being limited by nested structure. For example, you can implement functions like short links to facilitate user access.

// Route configuration
const routes = [
  { 
    path: '/'.component: Homepage,
    alias: '/home'}]Copy the code

💡 Route aliasing and route redirection are different, and while both can achieve the effect of mapping one path to another view component, if path/A has a route alias of /b, this means that when a user accesses/B, the URL stays at /b instead of jumping to/A, But the route matches used are/A routed, just as the user accesses/A.

The value of this option can be an array, providing multiple aliases, that is, implementing multiple urls pointing to the same page.

const routes = [
  {
    path: '/users/:id'.component: UsersByIdLayout,
    children: [
      // Render UserDetails for these three urls
      // - /users/24
      // - /users/24/profile
      / / - / 24
      { 
        path: 'profile'.component: UserDetails,
        alias: ['/:id'.' '[},],]Copy the code

💡 If the original path has parameters, please include the corresponding parameters in the alias for SEO specifications

Named view

Multiple < router-views > can be set up in a page template at the same time (parallel relationships, rather than through nested routines and nested

mappings), However, you have to set the name

The route should be configured with multiple components for the same route (if the number of components is less than the number of parallel

components, the corresponding redundant view components will not be rendered), i.e. the option components (not component) becomes an object. Set multiple components, each property is a component, the key is the named name of the

view, and the value is the component name

const router = createRouter({
  history: createWebHashHistory(),
  routes: [{path: '/'.// Corresponds to multiple components
      components: {
        // Default '
      
       ' component
      
        default: Home,
        LeftSidebar: LeftSidebar
        // The attribute name matches the 'name' attribute on '
      
       '
      
        LeftSidebar,
        RightSidebar,
      },
    },
  ],
})
Copy the code
<router-view class="view left-sidebar" name="LeftSidebar"></router-view>
<router-view class="view main-content"></router-view>
<router-view class="view right-sidebar" name="RightSidebar"></router-view>
Copy the code

💡 Both named views and nested routines allow you to set multiple view

components on a page, but for different purposes

  • Set multiple named views on the same page<router-view>, they can render nodes in a “parallel” relationship, allowing different routes to reuse the same layout template
  • Nested routines are set by multiple<couter-view>, the rendered nodes are parent-child nested relationships, typically used for local layout changes

💡 can mix named and nested views for more complex layouts

In the example above, the parent UserSettings component has a regular Nav component, as well as three nested routing components UserEmailsSubscriptions, UserProfile, UserProfilePreview, The components UserProfile and UserProfilePreview belong to the “parallel” relationship.

<! -- UserSettings.vue -->
<div>
  <h1>User Settings</h1>
  <NavBar />
  <router-view />
  <router-view name="helper" />
</div>
Copy the code
// Corresponding route configuration
{
  path: '/settings'.component: UserSettings,
  // Nested by
  children: [{path: 'emails'.component: UserEmailsSubscriptions
    }, 
    {
      path: 'profile'.// Name the view
      components: {
        default: UserProfile,
        helper: UserProfilePreview
      }
  }]
}
Copy the code

💡 In fact, the named view can be viewed as a more general routing-component mapping rule. If the page only needs a

, you can also use the components option when setting the route, but there is only one component in default: componentName.

redirect

In route configuration, the option redirect is used to achieve the redirect effect when the user accesses/A and navigates to/B.

The attribute value of this option can be a string representing a path, a name representing another route, an object containing routing information, or a method whose return value is one of the previous three forms representing a route.

// Route configuration
const routes = [
  {
    path: '/home'.redirect: '/'
  },
  // The destination of the redirect can also be a named route
  {
    path: '/home'.redirect: { name: 'homepage'}}, {// This dynamic route can be redirected
    // For example, redirect from route /home/hello to /home? q=hello
    path: '/home/:searchText'.redirect: route= > {
      The // method accepts the current route as an argument
      // Return redirects the string path/path object
      return { path: '/home'.query: { q: route.params.searchText } }
  },
]
Copy the code

💡 The value of this option can also be a relative path (for example, a string path that does not start with a slash is a relative path) for relative redirection

⚠️ navigational guard does not apply to jump routes, but to the route to which it points, so adding a beforeEnter guard for /home routes does not work in the example above.

💡 If the route is configured with redirect, omit the Component configuration because the route is never directly accessed and therefore has no components to render. The only exception is nested routines. If a route has children and Redirect attributes, it should also have component attributes.

Route lazy loading

Vue Router supports dynamic import, which is more efficient when components corresponding to different routes are divided into different code blocks and loaded when the route is accessed.

// import UserDetails from './views/UserDetails'
/ / replace
const UserDetails = () = > import('./views/UserDetails')

const router = createRouter({
  // ...
  routes: [{ path: '/users/:id'.component: UserDetails }],
})
Copy the code

💡 In general, it is a good idea to use dynamic imports for all routes. However, do not use asynchronous components in the routing, although asynchronous components can still be used in the routing component, but the routing component itself is dynamically imported.

💡 In the routing configuration, the component or Components option can receive a function that returns a Promise that will eventually resolve a component, so that the Vue Router will only get the component when it first enters the page, The cached data is then used, and you can perform more complex operations in promises

const UserDetails = () = >
  Promise.resolve({
    /* Component definition */
  })

const router = createRouter({
  // ...
  routes: [{ path: '/users/:id'.component: UserDetails }],
})
Copy the code

💡 If you use Webpack packaging, you can also separate components into blocks. For details, refer to the official documentation.

Viewing Existing Routes

Vue Router provides two ways to view existing routes in routing instances:

  • 🎉 router.hasRoute(name)Checks whether the route with the given name exists.
  • router.getRoutes()Return a containingAll routingAn array of records.

Add or delete the routing

The usual route setting is done when the route is instantiated. This is done in the routes property of the object passed to the method VueRouter. CreateRouter (). The value of this property is an array, each element being a route.

In some cases, however, you may want to add or remove routes while the application is already running. The Vue Router provides methods addRoute() and removeRoute() to add or remove routes.

Add the routing

Router.addroute () registers a new route using the route instance method

💡 If the newly added route matches the path location of the current page (perhaps the current path is matched by a dynamic route because it can match a large number of paths based on a pattern, whereas the newly added route may be a static route that matches the current path more “accurately”), You need to manually navigate router.push() or router.replace() to apply a new route (render a new view component)

If an application has only one dynamic route, any page entered, such as/About, will eventually render the Article component

const router = createRouter({
  history: createWebHistory(),
  routes: [{ path: '/:articleName'.component: Article }],
})
Copy the code

If we add a new static route in front

router.addRoute({ path: '/about'.component: About })
Copy the code

Although the new route is matched preferentially on the current page, the Article component is still displayed, and we need to manually navigate by calling router-.replace () to load the About component

router.replace(router.currentRoute.value.fullPath)
Copy the code

💡 If you are adding a route to the navigation guard at the same time, instead of calling router.replace(), you should simply return a route that triggers the Vue router to perform a redirection

// Add a route to the navigation guard
// The path of the new route is the same as the path of the navigation target, so the final return path is to.fullpath
router.beforeEach(to= > {
  if(! hasNecessaryRoute(to)) { router.addRoute(generateRoute(to))// Triggers a redirection
    return to.fullPath
  }
})
Copy the code

⚠️ The above examples satisfy two assumptions:

  • The newly added routing record is the same as that of thetoA location match actually results in a different location than the one we are trying to access.
  • After adding a new routehasNecessaryRoute()returnfalse?To avoid infinite redirection.

To add a nested route to an existing route, pass the route’s name as the first argument to router.addroute (), and then the second argument to the nested route

router.addRoute('admin', { path: 'settings'.component: AdminSettings })
Copy the code

Equivalent to

router.addRoute({
  name: 'admin'.path: '/admin'.component: Admin,
  children: [{ path: 'settings'.component: AdminSettings }],
})
Copy the code

Delete the routing

There are several different ways to delete an existing route, and when a route is deleted, all aliases and child routes are also deleted:

  • By adding a route with a name conflict. If you add a path with the same name as an existing path, the route is deleted first and then added

    router.addRoute({ path: '/about'.name: 'about'.component: About })
    // This will delete previously added routes because they have the same name and the name must be unique
    router.addRoute({ path: '/other'.name: 'about'.component: Other })
    Copy the code
  • A callback returned by calling router.addroute (), useful for unnamed routes

    const removeRoute = router.addRoute(routeRecord)
    removeRoute() // Delete the route if it exists
    Copy the code
  • Remove routes by name by using router.removeroute ()

    router.addRoute({ path: '/about'.name: 'about'.component: About })
    // Delete the route
    router.removeRoute('about')
    Copy the code

    💡 If you want to use this feature but want to avoid name conflicts, you can use Symbol as the name in the route.

Routing matching

Vue Router supports multiple route matching modes:

  • Most routes are composed of stringsStatic routing, it can match only one immutable path, for example/about
  • Further matching a series of paths according to some patternDynamic routing, e.g./users/:userId
  • Further, you can use regular expressions to customize matching patterns to match paths that need to satisfy complex conditions, 🎉The regular expression after the path parameterparenthesesIn the, e.g./:orderId(\d+)Matches a path that consists only of numbers. 💡 is used because of the need to escape backslashes\d+Matches multiple (at least one) digits

Dynamic routing

Dynamic routing maps all routes matched by a pattern (regular expression) to the same component.

Arguments to dynamic paths start with a colon:

// Route configuration is passed to 'createRouter'
const routes = [
  // The User component renders all users
  // The dynamic segment starts with a colon as the path parameter
  {
    path: '/user/:username'.component: User
  },
  {
    path: '/user/:username/posts/:postId'
    component: Post
  }
]
Copy the code

The matching parameter value (the dynamic segment of the path, called the path parameter) is added to the this.$route.params object. There are multiple path parameters set in the same route, which map to the corresponding field on this.$route.params.

/ / the User component
const User = {
  template: '<p>User {{ $route.params.username }}</p>',}/ / Post components
const Post = {
  template: ` 

User {{ $route.params.username }}

Post {{ $route.params.postId }}

`
} Copy the code

💡 The default regular expression used internally by actual dynamic routes is [^/]+ to extract parameters in the path by matching at least one character in the URL that is not a slash /.

⚠️ When matching the same component with a dynamic route, if only the dynamic path parameters change, the component does not trigger re-rendering, but instead reuses the original component, so the component’s lifecycle hook is no longer called. If you want to trigger component updates when route matching parameters change, you can set a listener watch to detect changes in $route.params, or use the beforeRouteUpdate hook function provided by the Vue Router to guard the route. You then manually trigger in the corresponding callback the operation that you would have done in the lifecycle hook function.

const User = {
  template: '... '.created() {
    this.$watch(
      () = > this.$route.params,
      (toParams, previousParams) = > {
        // Respond to routing changes...}})},const User = {
  template: '... '.async beforeRouteUpdate(to, from) {
    // Respond to routing changes...}},Copy the code

Repeatable parameters

If you need to match multiple parts of a path with similar structures, you can add the * or + modifier (which acts like a regular expression quantifier) after the path parameter to mark the parameter as repeatable rather than manually setting multiple path parameters.

const routes = [
  Chapters -> Chapters -> Chapters -> Chapters -> Chapters -> Chapters -> Chapters -> Chapters
  { path: '/:chapters+' },
  / / / / : chapters - > matching, / one/one/two/one/two/three, and so on
  { path: '/:chapters*'},]Copy the code

This gives an array of path parameters, such as using /: Chapters + dynamic path to match the path/A /b, which gives the path parameters the following values

console.log(this.$route.params.chapters) // ['a', 'b']
Copy the code

Optional parameter

If the part of path parameters in a dynamic route is optional, you can add? (This function is the same as regular expression quantifiers, indicating 0 or 1.)

const routes = [
  // Matches /users and /users/posva
  { path: '/users/:userId? ' },
  // Matches /users with /users/42
  { path: '/users/:userId(\d+)? '},]Copy the code

💡 * also technically marks a parameter as optional, but? A maximum of one parameter can be matched

404 Not Found Route

The path parameters of dynamic routes can only match characters between URL fragments (separated by /). 🎉 Since the wildcard * Router is removed from Vue Router Next, if you want to match any path (the most common scenario is to capture user access to an undefined route and then redirect to the 404 screen), you can use a custom path parameter regular expression, which is written in parentheses () after the path parameter

const routes = [
  // Matches everything that starts with '/user-' and places it in the path parameter afterUser
  AfterUser can be accessed via '$route.params.afteruser'
  { 
    path: '/user-:afterUser(.*)'.component: UserGeneric 
  },
  // Matches all of the contents of the path, and places it in the path parameter pathMatch
  $route.params.pathMatch = $route.params.pathMatch
  { 
    path: '/:pathMatch(.*)*'.name: 'NotFound'.component: NotFound
  },
]
Copy the code

The preceding example route parameters match the entire path, but the contents of the route are different due to different regular expressions

  • The path parameterafterUserIs a custom regular expression. *And what it matches is/user-Everything after the beginning, the path argument gets onestring, if the remaining path contents include/Delimiter, will proceedtranslationfor%2F, such as paths/user-ben/posts, then the string obtained by path parameter matching isben%2Fposts
  • The path parameterpathMatchIs the same as custom regular expressions. *, but then modifiers are used*To indicate that the path parameter is **Repeated parameter, so the path parameter yields aArray ** where in the path/Is to match the parse delimiter flag, get the array elements, such as the path/not/found, the path parameter is['not', 'found']

Both methods match the capture of the entire path, but the second method is recommended because when you manually push to a 404 route using the name of the route, such as NotFound, the delimiter/in the concatenated path will not be translated based on the passed parameters

this.$router.push({
  name: 'NotFound'.params: { pathMatch: ['not'.'found']}})Copy the code

💡 jumps to 404 not based on route name push but based on path string without concatenation/translation problems. The above two ways can be used

Sometimes a URL can match multiple routes. In this case, the matching priorities are defined in the order of routes. That is, in the route configuration, the route defined first has a higher priority. The matching sequence starts from top to bottom until a matching rule is found. So the 404 Not Found route is usually placed last, acting as a “bottom pocket” to catch some undefined path.

Embedded routines by

When an interface in a web page is composed of multiple layers of nested components, you can use nested routines to map these nested components to a corresponding path in the URL, and support multiple layers of deeply nested route-component mapping.

That is, a parent component can have its own

nested. When configuring a route, use the children option in the route (parent route) of this component to set the embedded router-child mapping rule.

/ / the parent component
const User = {
  template: '
      

User

// Render nested subcomponents based on routing here
'
}; / / child component const Profile = {  template: `<div class="page">Profile</div>` }; const Posts = {  template: `<div class="page">Posts</div>` } const router = new VueRouter({  // Routing rules  routes: [  // ...   {      path: '/user/:id'.component: User,      // Nested by      children: [{// UserProfile will be rendered inside User's <router-view>          // when /user/:id/profile is matched          path: 'profile'.component: UserProfile       },       {          // UserPosts will be rendered inside User's <router-view>          // when /user/:id/posts is matched          path: 'posts'.component: UserPosts       }     ]   }, ] }) Copy the code

The routing option children is just another routing array, like routes itself, so you can nest views as often as you want.

⚠️ A common route path starts with a /, but nested paths are not used because/is treated as the root path (absolute path). Using relative paths allows you to use nested components without having to set nested paths, making migration easier.

💡 If you want nested routes to support access to the upper level and the parent component’s

renders the page, you can set the nested router-child mapping rule with the children option and add a rule with an empty path string “”. Even if the nested part of the path is empty, a default nested component can be rendered.

const router = new VueRouter({
  routes: [{path: '/user/:id'.component: User,
      children: [
        // UserHome will be rendered inside User's <router-view>
        // when /user/:id is matched
        { path: ' '.component: UserHome }
        / /... other sub routes]]}})Copy the code

Routing navigation

The Vue Router can switch url paths in two ways

  • Using the component<router-link>Component, which is rendered on the page as<a>The label.
  • Using the method provided by the Vue Router to manually switch the URL path through JS is called programmatic navigation.

💡 🎉 All navigation in Vue Router Next, including the first navigation, is now asynchronous, that is, all methods of programmatic navigation return a Promise*, and asynchronous programming await or THEN is required if operations are to be performed based on navigation completion

For example, if the page has a pop-up navigation menu, we want to hide the menu after navigating to a new page. Because navigation is asynchronous, we need await until the promise returned by router.push resolves resovle or Reject before performing menu hiding

await router.push('/my-profile')
this.isMenuOpen = false
Copy the code

router-link

Use the

component to navigate, specifying the path via the property to, which renders as a
tag by default and wraps the contents of the component tag in it (slots, HTML support), similar to a URL toggle

<router-link to="/home">Home Page</router-link>
Copy the code

🔨 Render result

<a href="/home">Home Page</a>
Copy the code

💡 If you want the navigation to replace the current route after the link is clicked (that is, no history is left after navigation), you can set the component

property replace so that router-.replace () is called when the user clicks on the link, Instead of the router. Push ()

<router-link to="/abc" replace></router-link>
Copy the code

To attribute

The attribute to of the component

is used to describe which destination route the link navigates to. Its attribute value can be a string representing a path or an object describing the path

💡 Since the internal to value is immediately passed to router.push() for navigation when clicked, the to property has exactly the same rules as the value accepted by router.push.

<! -- string -->
<router-link to="/home">Home</router-link>
<! -- Render result -->
<! -- <a href="/home">Home</a> -->

<! -- JS expression with v-bind -->
<router-link :to="'/home'">Home</router-link>
<! -- Render result as above -->

<! Pass an object with path property -->
<router-link :to="{ path: '/home' }">Home</router-link>
<! -- Render result as above -->

<! -- Named route with path parameter -->
<router-link :to="{ name: 'user', params: { userId: '123' }}">User</router-link>

<! -->
<router-link :to="{ path: '/register', query: { plan: 'private' }}">Register</router-link>
<! -- Render result -->
<! -- <a href="/register? plan=private">Register</a> -->
Copy the code

Custom labels

🎉 Vue Router Next removed the

attribute tag. If you want to render this component as a different tag, you can add the attribute custom (default is false, The value of this attribute is true when added to the component

), indicating that the custom approach is used (rendering the component directly based on the slot content), rather than wrapping the slot content in the
element.

<router-link to="/home" custom>
  <span>Home Page</span>
</router-link>
Copy the code

🔨 Render result

 <span>Home Page</span>
Copy the code

Scope slot

The component

‘s scope slot V-slot exposes some parameters about the corresponding route (the route to which the attribute to points), which can then be used in the slot to customize the content rendered by the component.

⚠️ If you want to customize the rendering content of a component, remember to add the attribute custom to the component

to prevent the contents of the slot from being wrapped inside the
element by default, causing problems when rendering the custom content.

<router-link
  to="/about"
  custom
  v-slot="{ href, route, navigate, isActive, isExactActive }"
>
  <! -- a custom "link" component that receives routing information as props -->
  <NavLink :active="isActive" :href="href" @click="navigate">
    {{ route.fullPath }}
  </NavLink>
</router-link>
Copy the code
  • href: Parsing attributestoThe resulting URL will be used as the default<a>Elements of thehrefProperties. If nothing is provided, it containsbase
  • route: Parsing attributestoAfter the normalized address
  • navigate: The function that triggers navigation.Automatically blocks events if necessary, androuter-linkThe same. Such as:ctrlorcmd+ click will still be usednavigateignore
  • isActive: Application if requiredactive class, it istrueProperties are set on the componentactive-class)
  • isExactActive: Application if requiredexact active class, it istrueProperties are set on the componentexact-active-class)

💡 When the route is activated, the attribute of the component

matches the current URL path), and the root element of the component will add the class name. Router-link-active. Router-link-exact -active elements are styled with the class name. Router-link-exact -active

<router-link to="/">Index</router-link>
Copy the code

Programmatic navigation

Using the method provided by the Vue Router to manually switch the URL path through JS is called programmatic navigation

💡 these methods is to emulate the browser provides API window. The history, the following routing method is similar to Windows respectively. The history. The pushState, window. History. ReplaceState and window history. Go

💡 If the destination of the route navigation is the same as the component of the current route mapping, for example (dynamic routing) only parameters are changed, the component will be reused to optimize efficiency, that is, operations performed in the component lifecycle hook function will not be executed again, the beforeRouteUpdate hook function will be used for route guard. Or Watch listens for route changes and then manually triggers the desired action in the corresponding callback function.

The conventional navigation

The most common way to navigate isto use the method $router.push(location) to navigate the page to the specified location and add a new record to the history stack

💡 the corresponding declarative navigation is

The argument to this method can be a string representing a path or an object describing the path

// String path
router.push('/users/ben')

// The object with the path attribute
router.push({ path: '/users/ben' })

// Use the named route (assuming the path of the route is /users/:username) and add the path parameter (to create the URL for the way out, "fill in" the path parameter of the corresponding dynamic path).
// The result is /users/ Ben
router.push({ name: 'user'.params: { username: 'ben'}})// Object with path attribute and query parameter (to make way for creating URL)
// The result is /register? plan=private
router.push({ path: '/register'.query: { plan: 'private'}})// An object with the path attribute, hash
// result is /about#team
router.push({ path: '/about'.hash: '#team' })
Copy the code

💡 If the method $router.push() passes in an object describing a path that provides both the path attribute and the params attribute, then params is ignored. So when you pass objects, you either manually concatenate the parameters, or you supply them in the form of name and params

const username = 'ben'
// We can set up the URL manually, but we have to handle the encoding ourselves
router.push(`/user/${username}`) // -> /user/ben
/ / the same
router.push({ path: `/user/${username}` }) // -> /user/ben
// If possible, use 'name' and 'params' to benefit from automatic URL encoding
router.push({ name: 'user'.params: { username } }) // -> /user/ben
// 'params' cannot be used with' path '
router.push({ path: '/user'.params: { username } }) // -> /user
Copy the code

Alternate navigation

$router.push({path: location, replace: True}) (add to attribute repalce) or $router.replace(location) to navigate to the specified location, which does not add a new record to history, but replaces the current history record

💡 the corresponding declarative navigation is

History navigation

Use the $router.go(n) method to take n steps forward or backward in the history record, similar to window.history.go(n). If the value entered is too large or too small and the history record is insufficient, the jump will fail

// Move a record forward, the same as router.forward()
router.go(1)

// Return a record, the same as router.back()
router.go(-1)

// Forward 3 records
router.go(3)

// Silence fails if there are not so many records
router.go(-100)
router.go(100)
Copy the code

Navigation fault

Navigation failures: indicates a failed navigation where the desired navigation is blocked and the user remains on the same page:

  • The user is already on the page they are trying to navigate to
  • Navigation guardreturn falseOr callnext(false)Interrupted the navigation
  • A new navigation guard will appear while the current navigation guard is not complete
  • The navigational guard redirects to somewhere else by returning a route (such as all the way to a user who is not logged in)/loginPage)
  • The navigation guard threw an errorError

In the event of a Navigation Failure, the Promise returned by the Navigation is resolved as Navigation Failure, which is an instance of Error with some additional properties (normally, the navigational success Promise is resolved as a falsy value, usually undefined), So we can tell if we are navigating away from the current location:

const navigationResult = await router.push('/home')

if (navigationResult) {
  // Navigation is blocked
} else {
  // Successful navigation (including renavigation)
}
Copy the code

Identify navigation failures

To check if an error is coming from the router, you can use the isNavigationFailure function, which accepts a Promise of navigation as the first argument to determine the type of navigation resolution, and (optionally) NavigationFailureType to distinguish between different types of navigational failures

💡 If you pass only the first parameter isNavigationFailure(failure) and ignore the second parameter, then you will only check if the failure is a Navigation failure

🎉 NavigationFailureType there are three different types *, corresponding to different situations that cause the navigation to abort:

  • aborted: Returns in the navigation guardfalseOr call thenext(false)The navigation was interrupted.
  • cancelled: a new navigation is created before the current navigation is complete. For example, while waiting for the navigation guard, it is called againrouter.push.
  • duplicated: Navigation blocked because we are already in target position.
import { isNavigationFailure, NavigationFailureType } from 'vue-router'

// Try to leave the unsaved edit text interface
const failure = await router.push('/articles/2')
// If the navigation fails and the fault type is aborted
if (isNavigationFailure(failure, NavigationFailureType.aborted)) {
  // Display a small notification to the user
  showToast('You have unsaved changes, discard and leave anyway? ')}Copy the code

💡 All navigation failures have to and FROM attributes, which represent the target location and current location of the failed navigation, respectively

// Trying to access the admin page
router.push('/admin').then(failure= > {
  if (isNavigationFailure(failure, NavigationFailureType.redirected)) {
    failure.to.path // '/admin'
    failure.from.path / / '/'}})Copy the code

Detection redirection

Another navigational failure is that the navigational guard redirects somewhere else by returning a route, which triggers a new navigation that overrides the navigation in progress.

Unlike the return value of other navigational guards, redirection does not block navigation, but creates a new navigation that can be checked by reading the redirectedFrom property in the current routing address

await router.push('/my-profile')
if (router.currentRoute.value.redirectedFrom) {
  // redirectedFrom is the resolved routing address
}
Copy the code

Navigation guard

Navigational guard refers to the user access to a specific path, based on the conditional jump or cancel operations, so as to “protect” specific pages and data in the front. There are various opportunities to embed navigational guards, which can be global, proprietary to a single route, or component-level.

The 💡 guard resolves asynchronously, so the navigation waits until all the guards resolve

Complete route navigation parsing process:

  1. Navigation triggered
  2. Call the beforeRouteLeave guard in the deactivated component (guard within the component)
  3. Call the global beforeEach guard (global front-guard)
  4. Call the beforeRouteUpdate guard in a reusable component (guard within the component, routing updates, but component reuse)
  5. Call the beforeEnter guard in route configuration (guard exclusive to routes)
  6. Parse the asynchronous routing component
  7. Call the beforeRouteEnter guard in the active component (guard within the component)
  8. Call the global beforeResolve guard (global parse guard)
  9. Navigation confirmed
  10. Call the global afterEach hook (global afterguard)
  11. Triggering DOM updates
  12. callbeforeRouteEnterGuard passnextThe callback function ofThe created component instance is passed in as an argument to the callback function

💡 route parameters params or query query changes do not trigger enter/leave type navigational guards. You can respond to these changes by observing the $Route routing object with watch or by using the beforeRouteUpdate component internal guard.

The callback function

The ginseng

The routing guard callback normally takes two arguments:

  • toThe destination to be entered (route object Route)
  • fromThe current navigation is about to leave the route object route

💡 🎉 the guarded callback function can also receive a third (optional) argument, next, which is a function to call to verify navigation. But if the guard’s callback has a return value, you can omit next and encourage it.

⚠️ If this parameter is passed, make sure it is called strictly once so that the guard can resolve the Promise with “release” or the page will “get stuck” and fail to jump or display data. Its execution depends on the argument passed when called:

  • When next() does not pass arguments, it goes to the next hook in the pipe

  • Next (false) interrupts the current navigation

  • Next (‘/otherPath’) or next({path: ‘/otherPath’}) the current navigation is interrupted and a new navigation is performed. Jump to a different address

    💡 pass objects can customize the way to jump, such as next({replace: true, name: ‘home’}) to navigate to the home page instead of history.

  • Next (error) The argument passed to next is an instance of error, and the navigation is terminated.

// Redirect to the /login page if the user fails to authenticate
router.beforeEach((to, from, next) = > {
  if(to.name ! = ='Login' && !isAuthenticated) next({ name: 'Login' })
  else next()
})
Copy the code

The return value

The routing guard callback function has multiple return values and performs different navigation behaviors accordingly

  • Return no (that is, undefined) or true: perform the expected navigation

  • Return false: Cancel the current navigation

    router.beforeEach((to, from) = > {
      // ...
      // Return false to cancel navigation
      return false
    })
    Copy the code

    If the browser URL changes (either manually by the user or by the browser back button), the URL is reset to the address corresponding to the FROM route

  • Return a routing address: perform navigation to another address

    A routing address can be a string representing a path or an object describing routing information, with options such as replace: true or name: ‘home’. This is similar to calling router.push() to manually navigate to the returned address (a different navigation path than the user expected)

  • Throw an Error: unnavigate and invoke the callback registered with router.onerror ()

    It’s usually something unexpected

The following are commonly used hook functions for route guard. Select an appropriate hook function for route guard according to the actual situation:

Global front guard

Global routing guard beforeEach is called before entering any route. You can use the route instance method beforeEach() to define a global route guard that is called in the order in which it was created when a navigation is triggered.

router.beforeEach((to, from) = >{... })Copy the code

Global parsing guard

The global resolution guard beforeResolve is similar to the global front-guard beforeEach in that it is called every navigation, but it is called after the guard and asynchronous routing components have been resolved within all components and before the navigation is confirmed.

Global parsing guard is executed, the user has not yet entered the page, typically in the guard to fetch the data, the callback function can access the routing of the meta information, or perform some anticipation operation, such as permission to ask for, as soon as possible to prevent the user to access the corresponding page (in order to avoid the user even if entered the page, but because do not conform to the conditions, to perform some operation).

// Obtain the meta meta information of the destination route through the global resolution guard
// The route's meta information has the requiresCamera option (Boolean) to indicate that the redirect page requires the device camera
router.beforeResolve(async to => {
  if (to.meta.requiresCamera) {
    try {
      // You can try to gain access to the device camera in the route guard first
      await askForCameraPermission()
    } catch (error) {
      // Cancel navigation if permission cannot be obtained
      if (error instanceof NotAllowedError) {
        // ...
        return false
      } else {
        // Unexpected error, unnavigates and passes the error to the global handler
        throw error
      }
    }
  }
})
Copy the code

Global post-hook

The global afterEach hook is called when the navigation is validated. This hook does not accept the next function and does not change the navigation itself.

In this route guard, you can operate all the pages successfully navigated into, such as analyzing, changing page titles, declaring pages and other auxiliary functions.

router.afterEach((to, from) = > {
  sendToAnalytics(to.fullPath)
})
Copy the code

💡 Navigation failures can be used as the (optional) third parameter

router.afterEach((to, from, failure) = > {
  if(! failure) sendToAnalytics(to.fullPath) })Copy the code

Route exclusive guard

The exclusive routing guard beforeEnter is called only before entering a specific path. You can define specific routes during route configuration with the option beforeEnter.

// Route configuration
const routes = [
  {
    path: '/users/:id'.component: UserDetails,
    beforeEnter: (to, from) = > {
      // reject the navigation
      return false}},]Copy the code

💡 can pass an array of group functions to beforeEnter at 🎉 and they are executed according to this, which is useful when reusing guards for different routes

function removeQueryParams(to) {
  if (Object.keys(to.query).length)
    return { path: to.path, query: {}, hash: to.hash }
}

function removeHash(to) {
  if (to.hash) return { path: to.path, query: to.query, hash: ' '}}// Route configuration
const routes = [
  {
    path: '/users/:id'.component: UserDetails,
    beforeEnter: [removeQueryParams, removeHash], // Array of functions},]Copy the code

💡 Route exclusive guard beforeEnter fires only when entering a route, not when params, Query, or Hash changes.

Component internal guard

You can define route guards within a component that react when the component’s corresponding route changes.

Option type API

You can use the following options in the component to add an intra-component guard to the routing component

  • beforeRouteEnter(to, from) {… } called before the corresponding route to render the component is confirmed

    The component instance this cannot be accessed from the ⚠️ guard’s hook function because the guard is called before the navigation is confirmed, before the upcoming component is created. However, the component instance can be accessed by (optionally) passing a callback to the next function in the third argument

    beforeRouteEnter (to, from, next) {
      // Execute the next callback when the navigation is confirmed, and take the component instance as an argument to the callback method
      next(vm= > {
        // Access component instances through 'VM'})}Copy the code
  • beforeRouteUpdate(to, from) {… } is called when the current route changes but the component is being reused. It is typically used to respond when the route’s path parameter params or query parameter changes.

    For example, for the dynamic path /users/: ID, this hook is called when the user jumps between /users/1 and /users/2. Since the component is already mounted in this case, the navguard can access the component instance this

  • beforeRouteLeave(to, from) {… } when navigated away from the component’s corresponding route.

    The leave guard is usually used to prevent the user from leaving abruptly before saving the changes, and can be unnavigated by returning false.

    beforeRouteLeave (to, from) {
      const answer = window.confirm('Really want to leave? you have unsaved changes! ')
      if(! answer)return false
    }
    Copy the code

Modular API

🎉 Vue Router exposes update and leave guards as composite API functions, and you can define intra-component guards in the component’s option setup function using the following methods:

  • onBeforeTouteUpdata
  • onBeforeRouteLeave
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'

export default {
  setup() {
    // Same as beforeRouteLeave, 'this' cannot be accessed
    onBeforeRouteLeave((to, from) = > {
      const answer = window.confirm(
        'Do you really want to leave? you have unsaved changes! '
      )
      // Unnavigate and stay on the same page
      if(! answer)return false
    })

    const userData = ref()

    // Same as beforeRouteLeave, 'this' cannot be accessed
    onBeforeRouteUpdate(async (to, from) = > {// Get the user only when the ID changes, such as only the query or hash value has changed
      if(to.params.id ! = =from.params.id) {
        userData.value = await fetchUser(to.params.id)
      }
    })
  },
}
Copy the code

The combinatorial apis for guarding within 💡 components can be used in any component rendered by

; they do not have to be used directly on routing components like the option apis.

Data acquisition

When accessing a web page, you need to obtain data from the server. Generally, there are two opportunities to choose:

  • After the navigation is complete: Complete the navigation first, and then the followingComponent lifecycle hook functions, such ascreatedHook to get data. Display instructions such as Loading during data retrieval. This time is usually to fetch page data.
  • Before the navigation is complete: Before the navigation is complete, the data is retrieved from the guard hook function that the route enters, and the navigation is performed after the data is retrieved successfully. It is recommended to display some progress bars or other instructions during data retrieval because the user will be stuck in the current interface. This timing is generally based on validation, data acquisition of membership content.

⚠️ The reuse of components by Vue should be considered when using hook or route guard of component’s life cycle. If the hook function of component’s life cycle is used to obtain data, watch should be added to listen to the transformation of route $route to manually trigger the re-acquisition of data. If you use the route-guard hook function, you can get the data from the beforeRouteUpdate hook function of the intra-component guard so that the data can be updated smoothly even if the component is reused.

export default {
  data() {
    return {
      // ...}},created() {
    // watch route parameters to get data again
    this.$watch(
      () = > this.$route.params,
      () = > {
        this.fetchData()
      },
      // Get data after component is created.
      { immediate: true})},methods: {
    fetchData() {
      // ...}},}Copy the code
export default {
  data() {
    return {
      // ...}},// Get data before navigation to a new route
  // Access the component instance by calling the next method and place the retrieved data in the data option to make the data responsive
  beforeRouteEnter(to, from, next) {
    getPost(to.params.id, (err, post) = > {
      next(vm= > vm.setData(err, post))
    })
  },
  // The beforeRouteUpdate guard can respond to changes in route path parameters or query parameters
  async beforeRouteUpdate(to, from) {
    this.post = null
    try {
      this.post = await getPost(to.params.id)
    } catch (error) {
      this.error = error.toString()
    }
  },
}
Copy the code

Transition effects

You can use the
component to add a transition effect to all the routing components in the

, so that when switching routes, the components have the corresponding dynamic effect of entering/leaving.

🎉 But in Vue Router Next, the
component needs to be used in the

slot with the parameters exposed in the

scope slot V-slot:


  • Component: VNodes are normally passed to components<component>isProperty to dynamically switch routing components
  • route: Indicates the parsed route address
<router-view v-slot="{ Component, route }">
  <transition :name="route.meta.transition || 'fade'" mode="out-in">
    <keep-alive>
      <component
        :is="Component"
        :key="route.meta.usePathKey ? route.path : undefined"
      />
    </keep-alive>
   </transition>
</router-view>
Copy the code

💡 If you want each component of a route to have a different transition, you can add some transition-related fields to the meta information of the route, and obtain the attribute route.meta of the object exposed by the v-slot in the

scope. And bound in the < Transition > component’s property name

const routes = [
  {
    path: '/custom-transition'.component: PanelLeft,
    meta: { transition: 'slide-left'}, {},path: '/other-transition'.component: PanelRight,
    meta: { transition: 'slide-right'}},]Copy the code
<router-view v-slot="{ Component, route }">
  <! Use any custom transitions and fade back to 'fade' -->
  <transition :name="route.meta.transition || 'fade'">
    <component :is="Component" />
  </transition>
</router-view>
Copy the code

You can also use different transition effects based on the routing hierarchy

<! -- Use dynamic transition name -->
<router-view v-slot="{ Component, route }">
  <transition :name="route.meta.transition">
    <component :is="Component" />
  </transition>
</router-view>
Copy the code
// Use global post-hooks to dynamically add information to the meta field based on the depth of the path
router.afterEach((to, from) = > {
  const toDepth = to.path.split('/').length
  const fromDepth = from.path.split('/').length
  to.meta.transitionName = toDepth < fromDepth ? 'slide-right' : 'slide-left'
})
Copy the code

💡 If the animation effect does not take effect, usually because Vue is multiplexing the component, you can use $route information, such as $route.path or $route.fullPath, as the key attribute of the

component

Modular API

Access route and current route

When developing with the composite API, the component instance this is not accessible in the component’s option setup function, 🎉 so the Vue Router provides useRouter() and useRoute() functions, To access the route instance and the current route object instead of this.$router and this.$route, respectively

import { useRouter, useRoute } from 'vue-router'

export default {
  setup() {
    const router = useRouter()
    const route = useRoute()

    function pushWithQuery(query) {
      router.push({
        name: 'search'.query: {
          ...route.query,
        },
      })
    }
  },
}
Copy the code

💡 can still access $router and $route in the template without returning router or route in setup.

The route object is a reactive object, so any of its attributes can be listened on, but you should avoid listening on the entire Route object

import { useRoute } from 'vue-router'

export default {
  setup() {
    const route = useRoute()
    const userData = ref()

    // Listen for path parameters and get user information when changing
    watch(
      () = > route.params,
      async newParams => {
        userData.value = await fetchUser(newParams.id)
      }
    )
  },
}
Copy the code

Navigation guard

In addition, in order to set up the in-component guard in the composite API, 🎉 Vue Router exposes the update guard onBeforeTouteUpdata and leave guard onBeforeRouteLeave as the composite API functions

import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router'

export default {
  setup() {
    // Same as beforeRouteLeave, but not accessible to 'this'
    onBeforeRouteLeave((to, from) = > {
      const answer = window.confirm(
        'Do you really want to leave? you have unsaved changes! '
      )
      // Unnavigate and stay on the same page
      if(! answer)return false
    })

    const userData = ref()

    // Same as onBeforeRouteUpdate, but not accessible to 'this'
    onBeforeRouteUpdate(async (to, from) = > {// Get the user only when the ID changes, such as only the query or hash value has changed
      if(to.params.id ! = =from.params.id) {
        userData.value = await fetchUser(to.params.id)
      }
    })
  },
}
Copy the code

💡 composite API guards can also be used in any component rendered by

; they do not have to be used directly on routed components like the in-component guards.

Extension RouterLink

The component

provided by the Vue Router provides a large number of apis (route, href, isActive, isExactActive, navigate) via the scope slot V-slot, but does not cover all the requirements. We can extend and customize a < Cutom-router-link > component with the combined API useLink (RouterLink’s internal behavior is exposed as a combined API function)

import { RouterLink, useLink } from 'vue-router'

export default {
  name: 'AppLink'.props: {
    // If using TypeScript, add @ts-ignore. RouterLink.props,inactiveClass: String,},setup(props) {
    const { route, href, isActive, isExactActive, navigate } = useLink(props)
    // Add the isExternalLink attribute to determine whether the link points to the outside. Combined with CSS, the page can achieve different styles of external and internal links explicit
    const isExternalLink = computed(
      () = > typeof props.to === 'string' && props.to.startsWith('http'))return { isExternalLink, href, navigate, isActive }
  },
}
Copy the code

💡 In most midsize to large applications, it’s worth creating a custom RouterLink component to reuse throughout the application, such as links in navigation menus, adding external link hints, and inactive-class. See the official documentation for examples.

Route component parameters are transmitted

Pass routing information to the component as props to decouple the component from the route so that the component can be more generic.

To make the component more generic, you should not use $route in the component template to read the current routing information. However, if the component needs to use routing data, you can pass the routing information to the component as props. In the component, you need to set the corresponding props to receive the data.

There are three ways to pass routing information (or other data) to components as props

  • The Boolean model
  • Object pattern
  • The function mode

The Boolean model

When setting the route, if the props option is set to true, the route parameter route.params will be set to the component props property

⚠️ simply enabling parameter passing with the props option does not pass complete information about the path, such as the query parameter route.query

💡 For a route with multiple components (corresponding to multiple named views), you must “enable” the properties for each named view if you want the components to be decoupled from the route and routing-related information to be used in the component

const User = {
  // The component sets up props to receive data passed in by the route
  props: ['id'].template: '<div>User {{ id }}</div>'
}

const router = new VueRouter({
  routes: [{path: '/user/:id'.component: User, 
      props: true
    },
    // For routes that contain named views, you must add the 'props' option for each named view
    {
      path: '/user/:id'.components: { 
        default: User,
        sidebar: Sidebar
      },
      props: { 
        default: true.sidebar: false}}}])Copy the code

Object pattern

When setting up the route, if you set the option props to an object, it is passed to the component as static.

// Route Settings
const routes = [
  {
    path: '/promotion/from-newsletter'.component: Promotion,
    // Object mode
    props: { newsletterPopup: false}}]Copy the code

The function mode

When setting up a route, if the option props is set to a function, the data passed to the component is the return value of the function. This function can take the route object as an argument, so that it can get the data for the corresponding route

// Route Settings
const routes = [
  {
    path: '/search'.component: SearchUser,
    props: route= > ({ query: route.query.q })
  }
]
Copy the code

In the user access route /search? When q= Ben, the relevant data is passed to the component SearchUser, which gets prop {query: ‘Ben ‘}, so the component needs to preset Prop Query to receive data.