阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 路由与Pinia集成

路由与Pinia集成

作者:陈川 阅读数:30769人阅读 分类: Vue.js

路由和Pinia是Vue.js生态中两个核心工具,前者管理页面导航,后者处理全局状态。将它们结合使用可以构建更高效的单页应用。

路由基础配置

在Vue项目中安装vue-router和Pinia:

npm install vue-router pinia

创建基础路由文件通常放在src/router/index.js

import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'

const routes = [
  {
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    path: '/about',
    name: 'about',
    component: () => import('../views/AboutView.vue')
  }
]

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes
})

export default router

Pinia存储创建

典型的Pinia存储模块示例:

// stores/counter.js
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
    lastRoute: null
  }),
  actions: {
    increment() {
      this.count++
    },
    setLastRoute(routeName) {
      this.lastRoute = routeName
    }
  }
})

路由守卫集成

在导航守卫中使用Pinia存储:

// router/index.js
import { useCounterStore } from '@/stores/counter'

router.beforeEach((to, from) => {
  const store = useCounterStore()
  store.setLastRoute(from.name)
  
  if (to.meta.requiresAuth && !store.isAuthenticated) {
    return '/login'
  }
})

组件内访问路由状态

在组件中同时使用路由和Pinia:

<script setup>
import { useRoute } from 'vue-router'
import { useCounterStore } from '@/stores/counter'

const route = useRoute()
const counterStore = useCounterStore()

// 响应式获取当前路由参数
const userId = computed(() => route.params.id)

// 修改存储状态
function incrementWithRoute() {
  counterStore.increment()
  console.log('Current route:', route.fullPath)
}
</script>

<template>
  <div>
    <p>User ID: {{ userId }}</p>
    <button @click="incrementWithRoute">Increment</button>
  </div>
</template>

动态路由与存储同步

实现基于存储状态的动态路由加载:

// router/index.js
export function setupDynamicRoutes(router, store) {
  store.$onAction(({ name, after }) => {
    if (name === 'loadUserPermissions') {
      after(() => {
        const routes = store.permissions.map(perm => ({
          path: `/${perm}`,
          component: () => import(`@/views/${perm}View.vue`)
        }))
        routes.forEach(route => router.addRoute(route))
      })
    }
  })
}

路由元信息与存储

利用路由元信息增强状态管理:

const routes = [
  {
    path: '/admin',
    meta: {
      requiresStore: 'admin',
      storeAction: 'fetchAdminData'
    }
  }
]

router.beforeEach(async (to) => {
  if (to.meta.requiresStore) {
    const store = useStore()
    await store[to.meta.storeAction]()
  }
})

服务端渲染考虑

在SSR环境中需要注意的点:

// 在entry-server.js中
export default async function (context) {
  const pinia = createPinia()
  const app = createApp(App)
  
  app.use(pinia)
  const router = createRouter()
  
  // 同步服务器端状态
  if (context.piniaState) {
    pinia.state.value = context.piniaState
  }

  await router.push(context.url)
  await router.isReady()
  
  return { app, router, pinia }
}

测试策略

编写测试时的实用模式:

import { setActivePinia, createPinia } from 'pinia'
import { createRouter, createWebHistory } from 'vue-router'
import { mount } from '@vue/test-utils'

test('uses pinia store with router', async () => {
  setActivePinia(createPinia())
  const router = createRouter({
    history: createWebHistory(),
    routes: []
  })
  
  const wrapper = mount(Component, {
    global: {
      plugins: [router]
    }
  })
  
  await router.push('/test-route')
  expect(wrapper.vm.$route.path).toBe('/test-route')
})

性能优化技巧

减少不必要的状态加载:

router.beforeEach((to) => {
  if (to.meta.shouldPrefetch) {
    const store = useStore()
    // 仅当数据不存在时才加载
    if (!store.isDataLoaded) {
      store.loadInitialData()
    }
  }
})

类型安全集成

使用TypeScript增强类型检查:

// types/router.d.ts
import 'vue-router'

declare module 'vue-router' {
  interface RouteMeta {
    requiresStore?: string
    storeAction?: keyof typeof useStore
  }
}

// stores/index.ts
export const useStore = defineStore('main', {
  actions: {
    fetchAdminData(): Promise<void> {
      // 实现逻辑
    }
  }
})

错误处理模式

统一处理导航错误:

router.onError((error) => {
  const store = useErrorStore()
  store.logNavigationError(error)
  
  if (isCriticalError(error)) {
    router.push('/system-error')
  }
})

路由懒加载优化

结合Pinia实现智能预加载:

// 在存储中跟踪路由加载状态
const useRouteStore = defineStore('routes', {
  state: () => ({
    loadedRoutes: new Set()
  }),
  actions: {
    markRouteLoaded(routeName) {
      this.loadedRoutes.add(routeName)
    }
  }
})

// 包装懒加载组件
function smartImport(routeName) {
  const routeStore = useRouteStore()
  return {
    component: import(`@/views/${routeName}.vue`),
    loadingComponent: routeStore.loadedRoutes.has(routeName) 
      ? null 
      : LoadingSpinner
  }
}

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌