vue动态路由导入

静态路由的回顾

  • 1.创建router/index.js文件,这里只有一些简单的页面
import Vue from 'vue'
import Router from 'vue-router'
import Login from '@/view/login/Login'
import Index from '@/layout/Index'
import Welcome from '@/layout/welcome/Welcome'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/login',
      name: 'Login',
      component: Login
    },
    {
      path: '/',
      component: Index,
      redirect: '/welcome',
      meta: {requireAuth: true},
      children: [
        {
          path: '/welcome',
          component: Welcome,
          name: '首页',
          meta: {title: '首页', requireAuth: true}
        }
      ]
    }
  ]
})

2.创建router/permission.js文件,配置导航守卫,可以在每次路由跳转前做一些操作,待会获取动态路由操作也在这里配置

import router from '@/router/index'
import 'element-ui/lib/theme-chalk/index.css'
import '@fortawesome/fontawesome-free/css/all.min.css'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'

NProgress.configure({
  easing: 'ease', // 动画方式
  speed: 500, // 递增进度条的速度
  showSpinner: false, // 是否显示加载ico
  trickleSpeed: 200, // 自动递增间隔
  minimum: 0.3 // 初始化时的最小百分比
})
// 白名单
const whiteList = ['/login'] // no redirect whitelist

// 导航守卫
router.beforeEach((to, from, next) => {
  NProgress.start()
  if (to.meta.requireAuth) {
    // 判断该路由是否需要登录权限
    if (sessionStorage.getItem('loginName') !== null) {
      // 判断本地是否存在token
      next()
      // 这里是待会获取异步路由的地方
    } else {
      // 未登录,跳转到登陆页面
      next({
        path: '/login'
      })
    }
  } else {
    if (whiteList.indexOf(to.path) !== -1) {
      next()
    } else {
      if (sessionStorage.getItem('loginName') !== null) {
        // 判断本地是否存在token
        next(`/?redirect=${to.path}`)
      } else {
        next(`/login?redirect=${to.path}`)
      }
    }
  }
})

router.afterEach(() => {
  // 在即将进入新的页面组件前,关闭掉进度条
  NProgress.done()
})

3.在main.js里引入刚才创建的router下的index.js文件和permission.js文件,如下

import router from '@/router'
import './router/permission'

new Vue({
  el: '#app',
  router,
  store,
  components: { App },
  template: '<App/>'
})

4.在App入口中放入路由跳转的视图区,跳转的路由页面都显示在这里

<div id="app">
    <router-view />
</div>

现在静态路由就配好了,可以正常的跳转了!
1.首先呢,router/index.js,没有什么需要改的,把你需要动态获取的路由信息删除掉即可,可以留一部分静态路由,如登录页,首页等等,若全删,routes赋为[]即可。

2.创建一个文件,我命名为getAsyncRouter.js,用来处理获取到的动态路由信息。

// 用于处理动态菜单数据,将其转为 route 形式
export function fnAddDynamicMenuRoutes (menuList = [], routes = []) {
  // 用于保存普通路由数据
  let temp = []
  // 用于保存存在子路由的路由数据
  let route = []
  // 遍历数据
  for (let i = 0; i < menuList.length; i++) {
    // 存在子路由,则递归遍历,并返回数据作为 children 保存
    if (menuList[i].children && menuList[i].children.length > 0) {
      // 获取路由的基本格式
      route = getRoute(menuList[i])
      // 递归处理子路由数据,并返回,将其作为路由的 children 保存
      route.children = fnAddDynamicMenuRoutes(menuList[i].children)
      // 保存存在子路由的路由
      routes.push(route)
    } else {
      // 保存普通路由
      temp.push(getRoute(menuList[i]))
    }
  }
  // 返回路由结果
  return routes.concat(temp)
}

// 返回路由的基本格式
function getRoute (item) {
  // 路由基本格式
  let route = {
    // 路由的路径
    path: item.url,
    // 路由名
    name: item.name,
    // 路由所在组件
    // component: (resolve) => require([`@/layout/Index`], resolve),
    component: (resolve) => require([`@/view${item.curl}`], resolve),
    meta: {
      id: item.id,
      icon: item.icon
    },
    // 路由的子路由
    children: []
  }
  // 返回 route
  return route
}

这里是两个函数,把获取到的数据处理成路由表数据,将其变化成 route 的形式。

fnAddDynamicMenuRoutes 用于递归菜单数据。 getRoute 用于返回某个数据转换的 路由格式。
注释写的应该算是很详细了,主要讲一下思路:   对数据进行遍历,   定义两个数组(temp,route),temp
用于保存没有子路由的路由,route 用于保存存在子路由的路由。   如果某个数据存在
子路由,则对子路由进行遍历,并将其返回结果作为当前数据的 children。并使用 route 保存路由。
  如果某个数据不存在子路由,则直接使用 temp 保存路由。   最后,返回两者拼接的结果,即为转换后的数据。 route 格式一般如下:
  path:指路由路径(可以根据路径定位路由)。   name:指路由名(可以根据路由名定位路由)。
  component:指路由所在的组件。   children:指的是路由组件中嵌套的子路由。   meta:用于定义路由的一些元信息。

这里有个大坑!!! 在配置component的时候,需要动态导入组件,也就是vue异步组件

综上所述,就是说,组件的导入可以使用字符串拼接的方式导入,可以使用模板字符串导入(字符串中含有变量),但是使用模板字符串导入时不能够只使用变量!!必须指定一个目录,不能全用变量代替!

3.有了处理动态路由数据的函数,那就需要在合适的地方调用,以发挥作用。这时就需要用到beforeEach了,在router/permission.js文件,配置导航守卫,可以在每次路由跳转前做一些操作,这里就是获取动态路由了

import router from '@/router/index'
import 'element-ui/lib/theme-chalk/index.css'
import '@fortawesome/fontawesome-free/css/all.min.css'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import {fnAddDynamicMenuRoutes} from '@/router/getAsyncRouter'
import {getRouter} from '@/api/sys/Menu'
import store from '@/store'


NProgress.configure({
  easing: 'ease', // 动画方式
  speed: 500, // 递增进度条的速度
  showSpinner: false, // 是否显示加载ico
  trickleSpeed: 200, // 自动递增间隔
  minimum: 0.3 // 初始化时的最小百分比
})
// 白名单
const whiteList = ['/login'] // no redirect whitelist

// 导航守卫
router.beforeEach((to, from, next) => {
  NProgress.start()
  try {
    // 判断是否已经获取过动态菜单,未获取,则需要获取一次
    if (store.getters.dynamicRoutes.length === 0) {
      if (whiteList.indexOf(to.path) !== -1) {
        next()
      } else {
        getRouter().then(res => {
          if (res.code === 0) {
            let menuRouter = fnAddDynamicMenuRoutes(res.data[0].children)
            store.dispatch('app/dynamicRoutes', menuRouter).then(() => {
              router.addRoutes(store.getters.dynamicRoutes)
              next({...to, replace: true})
            })
          } else {
            console.log('获取动态路由失败!')
            next({path: '/login'})
          }
        })
      }
    } else {
      // 路由已存在或已缓存路由
      if (to.meta.requireAuth) {
        if (sessionStorage.getItem('loginName') !== null) {
          // 判断本地是否存在token
          next()
        } else {
          // 未登录,跳转到登陆页面
          next({path: '/login'})
        }
      } else {
        if (whiteList.indexOf(to.path) !== -1) {
          next()
        } else {
          if (sessionStorage.getItem('loginName') !== null) {
            // 判断本地是否存在token
            next(`/?redirect=${to.path}`)
          } else {
            next(`/login?redirect=${to.path}`)
          }
        }
      }
    }
  } catch (error) {
    console.log('出错了')
    next(`/login?redirect=${to.path}`)
  }
})

router.afterEach(() => {
  // 在即将进入新的页面组件前,关闭掉进度条
  NProgress.done()
})

4接下来看一看,store的写法

const state = {
  dynamicRoutes: []
}

const mutations = {
  DYNAMIC_ROUTES (state, routes) {
    state.dynamicRoutes = routes
  }
}

const actions = {
  dynamicRoutes ({commit}, routes) {
    commit('DYNAMIC_ROUTES', routes)
  }
}

在刷新页面时遇到一个问题,动态路由表会随着vuex的刷新而消失。

处理:这里在app.vue页面刷新时利用sessionStorage存储一下store,防止刷新丢失vuex。

export default {
  name: 'App',
  created () {
    // 在页面加载时读取sessionStorage里的状态信息
    if (sessionStorage.getItem('storeData')) {
      this.$store.replaceState(Object.assign({}, this.$store.state, JSON.parse(sessionStorage.getItem('storeData'))))
    }
    // 在页面刷新时将vuex里的信息保存到sessionStorage里
    window.addEventListener('beforeunload', () => {
      sessionStorage.setItem('storeData', JSON.stringify(this.$store.state))
    })
    // 兼容iphone手机
    window.addEventListener('pagehide', () => {
      sessionStorage.setItem('storeData', JSON.stringify(this.$store.state))
    })
  }
}
//登录的时候也调用一下
getRouter().then(res => {
  if (res.code === 0) {
    let menuRouter = fnAddDynamicMenuRoutes(res.data[0].children)
    store.dispatch('app/dynamicRoutes', menuRouter).then(() => {
      router.addRoutes(store.getters.dynamicRoutes)
    })
    console.log(store.getters.dynamicRoutes)
  } else {
    console.log('获取动态路由失败!')
    router.push('/login')
  }
})
<think>首先,用户意图是了解Vue.js动态路由的实现方法及示例。用户提到了“动态路由”,所以我需要基于Vue Router来解释如何实现动态路由。 从系统级指令中,我需要: - 所有行内数学表达式用$...$格式(但这里可能不涉及数学表达式)。 - 独立公式用$$...$$格式(同样,可能不适用)。 - LaTeX语法正确(但在这个上下文中,更多是关于代码)。 - 使用中文回答。 - 生成相关问题。 - 在回答中引用的段落末尾添加引用标识。 - 回答结构清晰,帮助用户逐步解决问题。 参考提供的引用: - [^1]:介绍路由概念和Vue Router。 - [^2]:Vue Router的基本使用。 - [^3]:Vue Router定义多个路由。 - [^4]:一个HTML文件加载JS文件的例子。 用户意图是动态路由,所以我会专注于Vue Router的动态路由特性,如动态路径参数、嵌套路由等。 结构化我的回答: 1. **引言**:简要介绍动态路由Vue.js中的作用。 2. **实现方法**:解释如何定义动态路由。 - 使用路由参数(如`:id`)。 - 在组件中访问路由参数。 - 动态添加路由(使用`router.addRoute()`)。 3. **示例**:提供代码示例。 - 一个简单的例子:显示用户详情。 - 另一个例子:动态添加路由。 4. **生成相关问题**:在最后添加相关问题。 确保使用中文。 在引用段落末尾添加引用标识。例如,如果我从引用[^1]中借用概念,就在那里添加[^1]。 可能的引用点: - 概念部分可以引用[^1]或[^3]。 - 基本使用引用[^2]。 - 文件加载引用[^4],但可能不直接相关。 生成相关问题: - 基于动态路由的常见问题,如性能优化、实际应用等。 回答结构: - 开头:解释动态路由。 - 方法:逐步实现。 - 示例:代码块。 - 结尾:相关问题。 代码格式:使用代码块,如示例中所示。 最终输出应包括: - 回答部分。 - §§相关问题§§部分。</think>### Vue.js 动态路由实现方法及示例 在 Vue.js 中,动态路由允许你根据 URL 参数动态加载和渲染组件,这在处理用户详情、分类页面等场景非常有用。Vue Router 是官方提供的路由管理器,支持动态路径参数和动态路由添加功能[^3]。下面我将一步步解释实现方法,并提供完整示例。 #### 1. 动态路由的基本实现方法 动态路由的核心是使用 **路径参数**(如 `:id`)在路由定义中标记动态部分。当用户访问 URL 时,Vue Router 会解析参数并传递给组件。以下是关键步骤: - **定义动态路径**:在路由配置中使用冒号(`:`)定义参数,例如 `path: '/user/:id'`。 - **访问路由参数**:在组件中通过 `this.$route.params` 或 Vue Router 的 Composition API(如 `useRoute()`)获取参数值。 - **动态添加路由**:对于运行时添加路由(如基于用户权限),使用 `router.addRoute()` 方法[^2]。 这种机制让应用程序能响应 URL 变化,实现无刷新页面切换[^1]。 #### 2. 完整代码示例 以下是一个基于 Vue 3 和 Vue Router 4 的动态路由示例。假设我们有一个用户详情页面,URL 如 `/user/123` 会动态加载用户数据。 **步骤 1: 安装和设置 Vue Router** 首先,确保项目中已安装 Vue Router。如果未安装,运行: ```bash npm install vue-router@4 ``` **步骤 2: 定义路由配置** 在 `src/router/index.js` 文件中,设置动态路由: ```javascript import { createRouter, createWebHistory } from 'vue-router'; import Home from '../views/Home.vue'; import UserDetail from '../views/UserDetail.vue'; const routes = [ { path: '/', name: 'Home', component: Home }, { path: '/user/:id', // 动态路径参数 :id name: 'UserDetail', component: UserDetail, props: true // 将路由参数作为 props 传递给组件 } ]; const router = createRouter({ history: createWebHistory(), routes }); export default router; ``` **步骤 3: 创建组件** 在 `src/views/UserDetail.vue` 中,访问动态参数并显示用户详情: ```vue <template> <div> <h2>用户详情</h2> <p>用户ID: {{ userId }}</p> <p v-if="userData">用户名: {{ userData.name }}</p> <p v-else>加载中...</p> </div> </template> <script> import { ref, onMounted } from 'vue'; import { useRoute } from 'vue-router'; export default { props: ['id'], // 接收路由参数作为 prop setup(props) { const route = useRoute(); const userId = ref(props.id || route.params.id); // 通过 prop 或 $route 获取参数 const userData = ref(null); onMounted(async () => { // 模拟 API 调用,基于参数获取数据 const response = await fetch(`https://jsonplaceholder.typicode.com/users/${userId.value}`); userData.value = await response.json(); }); return { userId, userData }; } }; </script> ``` **步骤 4: 动态添加路由示例** 如果需要运行时添加路由(如用户登录后添加权限路由),在组件或入口文件中使用: ```javascript // 在 src/main.js 或组件中 import router from './router'; // 模拟条件:用户登录后添加新路由 if (userIsAdmin) { router.addRoute({ path: '/admin', name: 'Admin', component: () => import('./views/Admin.vue') // 懒加载组件 }); } ``` #### 3. 关键点说明 - **参数传递**:使用 `props: true` 将路由参数作为组件 props 传递,提高代码可读性[^2]。 - **响应式更新**:当 URL 参数变化时(如从 `/user/1` 到 `/user/2`),组件会自动重新渲染,无需手动监听。 - **懒加载**:动态导入组件(`component: () => import(...)`)优化性能[^3]。 - **错误处理**:添加 `path: '/:catchAll(.*)'` 路由捕获未匹配的 URL,避免空白页面。 #### 4. 实际应用场景 - 用户管理系统:根据用户 ID 显示详情页。 - 电商平台:动态加载产品分类页面(如 `/category/:categoryId`)。 - 权限控制:基于用户角色动态添加路由,确保安全访问[^1]。 动态路由提升了 SPA 的灵活性和用户体验,避免了传统多页面应用的刷新问题[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值