vue-router

repository·main·Indexed 26 days ago

https://github.com/vuejs/router

The official router for the Vue.js ecosystem, enabling single-page application (SPA) navigation and routing. Includes documentation for version 5 and experimental features such as Data Loaders via the DataLoaderPlugin, including defineBasicLoader for reactive data fetching and defineColadaLoader for asynchronous state management with caching and SSR support.

Tokens
44.4K
Snippets
151
Records
235
Agent score
88%

What's inside vue-router

  1. Introduction to Vue Router

    main

    Vue Router is the official router for Vue.js, designed to facilitate the building of Single Page Applications (SPAs). It provides deep integration with the Vue.js core and supports several key features:

    • Nested routes mapping: Define routes that render inside other routes.
    • Dynamic Routing: Use route parameters to handle dynamic content.
    • Modular configuration: Component-based router setup.
    • Navigation features: Support for route params, query strings, and wildcards.
    • Transitions: View transition effects using the Vue.js transition system.
    • Navigation control: Fine-grained control over how users navigate.
    • Automatic styling: Links automatically receive active CSS classes.
    • History modes: Support for both HTML5 history mode and hash mode.
    • Scroll Behavior: Customizable scroll behavior during navigation.
    • URL Encoding: Proper encoding for URLs.
  2. Perform relative redirecting

    main

    You can use a function in the redirect property to calculate a new path relative to the current one. The function receives the target route object, allowing you to manipulate the path string (e.g., using .replace()) to create relative redirects.

    const routes = [
      {
        // will always redirect /users/123/posts to /users/123/profile
        path: '/users/:id/posts',
        redirect: to => {
          return to.path.replace(/posts$/, 'profile')
        },
      },
    ]
  3. Configure Memory History Mode

    main

    Memory mode does not interact with the browser URL and does not automatically trigger initial navigation. This mode is ideal for Node.js environments or Server-Side Rendering (SSR).

    Requirements & Caveats:

    • You must manually push the initial navigation after calling app.use(router).
    • If used in a browser, there will be no browser history (no back/forward button support).
    import { createRouter, createMemoryHistory } from 'vue-router'
    
    const router = createRouter({
      history: createMemoryHistory(),
      routes: [
        // ...
      ],
    })
  4. Implement File-Based Routing with Vue Router

    main

    Vue Router supports file-based routing where the directory structure in src/pages (by default) automatically generates your application's routing structure. This eliminates the need to manually maintain a routes array.

    Basic Folder Structure

    • src/pages/index.vue $\rightarrow$ /
    • src/pages/about.vue $\rightarrow$ /about
    • src/pages/users/index.vue $\rightarrow$ /users
    • src/pages/users/[id].vue $\rightarrow$ /users/:id

    Key Conventions

    • Index Routes: Use index.vue (must be lowercase) to generate an empty path for a directory (e.g., src/pages/users/index.vue $\rightarrow$ /users).
    • Nested Routes: Define a .vue file with the same name as a folder to create a parent route. The contents of the folder will be rendered within that component's <RouterView>.
    • Nested Routes without UI Nesting: To add a URL segment (like /users/create) without nesting the component inside a parent layout, use a dot in the filename: src/pages/users.create.vue $\rightarrow$ /users/create.
    src/pages/
    ├── index.vue
    ├── about.vue
    └── users/
        ├── index.vue
        └── [id].vue
  5. Define and use a Basic Loader

    main

    Data Loaders are defined using composables like defineBasicLoader. You must define and export the loader from a page component. The loader is associated with a route pattern (e.g., '/users/[id]').

    When a user navigates to a matching route, the loader executes, and Vue Router automatically awaits the data before completing the navigation. This ensures the component renders with the required data already available.

    Inside the component's <script setup>, you call the exported loader function to access the loading state and the fetched data.

    <script lang="ts">
    import 'vue-router/auto-routes'
    import { defineBasicLoader } from 'vue-router/experimental'
    import { getUserById } from '../api'
    
    // Define and export the loader from the page component
    export const useUserData = defineBasicLoader('/users/[id]', async (route) => {
      return getUserById(route.params.id)
    })
    </script>
    
    <script setup lang="ts">
    // Use the exported loader to access state
    const {
      data: user,    // the data returned by the loader
      isLoading,     // a boolean indicating if the loader is fetching data
      error,         // an error object if the loader failed
      reload,        // a function to refetch the data without navigating
    } = useUserData()
    </script>
    
    <template>
      <main>
        <p v-if="isLoading">Loading...</p>
        <template v-else-if="error">
          <p>{{ error.message }}</p>
          <button @click="reload()">Retry</button>
        </template>
        <template v-else>
          <p>{{ user }}</p>
        </template>
      </main>
    </template>
  6. Handle asynchronous navigation with router.push

    main

    Navigations in Vue Router are asynchronous. When calling router.push, you should await the returned Promise to ensure subsequent code executes only after the navigation attempt has finished.

    Note that a resolved promise does not necessarily mean a successful page change; it could also mean a navigation failure occurred.

    await router.push('/my-profile')
    // This code runs after the navigation attempt finishes
    this.isMenuOpen = false
  7. Use KeepAlive and Transition with RouterView

    main

    To keep route components alive or apply transitions between route changes, wrap the <component :is="Component" /> inside the <router-view> slot using Vue's built-in <keep-alive> or <transition> components.

    <!-- Using KeepAlive -->
    <router-view v-slot="{ Component }">
      <keep-alive>
        <component :is="Component" />
      </keep-alive>
    </router-view>
    
    <!-- Using Transition -->
    <router-view v-slot="{ Component }">
      <transition>
        <component :is="Component" />
      </transition>
    </router-view>
    
    <!-- Using both KeepAlive inside Transition -->
    <router-view v-slot="{ Component }">
      <transition>
        <keep-alive>
          <component :is="Component" />
        </keep-alive>
      </transition>
    </router-view>
  8. Configure the `base` option in history

    main

    The base option is no longer a top-level router option. It must be passed as the first argument to the history function (e.g., createWebHistory).

    import { createRouter, createWebHistory } from 'vue-router'
    
    createRouter({
      history: createWebHistory('/base-directory/'),
      routes: [],
    })
  9. Apply Parsers to Path Parameters

    main

    There are two ways to apply a parser to a path parameter:

    1. File-based naming: Rename your route file to include the parser name in the segment, e.g., [id=int].vue or [productId=uuid].vue.
    2. definePage configuration: Declare the parser within the definePage macro.
    <!-- src/pages/users/[id].vue -->
    <script setup lang="ts">
    definePage({
      params: {
        path: {
          id: 'number',
        },
      },
    })
    </script>
  10. Migrate an existing project to file-based routing

    main

    To migrate from manual route arrays to file-based routing:

    1. Move your page components to src/pages and rename them according to file-based conventions (e.g., Home.vue becomes index.vue).
    2. Import routes and handleHotUpdate from vue-router/auto-routes.
    3. Replace your manual routes array with the imported routes.
    4. Use handleHotUpdate(router) within an if (import.meta.hot) block to allow route updates at runtime without page reloads.
    import { createRouter, createWebHistory } from 'vue-router'
    import { routes, handleHotUpdate } from 'vue-router/auto-routes'
    
    export const router = createRouter({
      history: createWebHistory(),
      routes,
    })
    
    // This will update routes at runtime without reloading the page
    if (import.meta.hot) {
      handleHotUpdate(router)
    }
  11. Replace `<router-link>` `append` prop with manual concatenation

    main

    The append prop is removed. To achieve the same behavior, manually concatenate the path. You can define a global append function on your App instance to simplify this.

    <!-- Replace this: -->
    <router-link to="child-route" append>to relative child</router-link>
    
    <!-- With this: -->
    <router-link :to="append($route.path, 'child-route')">
      to relative child
    </router-link>
    // Define global helper
    app.config.globalProperties.append = (path, pathToAppend) =>
      path + (path.endsWith('/') ? '' : '/') + pathToAppend