Vue Router реализует динамическую маршрутизацию и решения распространенных проблем

Vue.js

Что такое динамическая маршрутизация

Личное понимание: динамическая маршрутизация отличается от обычной статической маршрутизации, и список маршрутизации сайта может быть изменен в соответствии с различными «факторами». Большинство общих динамических маршрутов используются для реализации: разные пользователи в многопользовательской системе разрешений отображают разные навигационные меню.

Как реализовать динамическую маршрутизацию с помощью Vue Router

VueСуществует два способа реализации динамической маршрутизации в проекте:

  1. Внешний интерфейс определяет все маршруты и динамически отображает маршруты в соответствии с разрешениями роли пользователя при входе в систему;
  2. Маршрут хранится в базе данных, а интерфейс получает через интерфейс список маршрутов, соответствующий текущему пользователю, и отображает его;

Первый способ во многихVue UI AdminВсе вышеперечисленное уже реализовано, вы можете прочитать их исходный код, чтобы понять конкретные идеи реализации, поэтому я не буду здесь слишком много распространяться. Второй метод тоже сейчас более распространен, потому что он используется в последних проектах, поэтому я расскажу о нем отдельно.Vue RouterНекоторые функции реализуют динамическую маршрутизацию с преобладанием серверной части.

Используемые функции

Глобальная передняя защита Vue Router

Официальное объяснение веб-сайта

Здесь мы в основном используем функцию «внешнего интерфейса» глобальной внешней защиты для внедрения списка маршрутизации, используемого текущим пользователем, на страницу до загрузки страницы.RouterВ примере метод, используемый для инъекции, следующий:router.addRoutesметод.

Метод экземпляра Vue Router router.addRoutes

Официальное объяснение веб-сайта

router.addRoutesметод может бытьRouterЭкземпляр динамически добавляет правила маршрутизации, что просто предоставляет нам метод внедрения для реализации динамической маршрутизации.

Отложенная загрузка маршрутизации Vue Router

Официальное объяснение веб-сайта

Эта функция ленивой загрузки не является необходимой функцией динамической маршрутизации, но поскольку эта возможность предусмотрена, она используется непосредственно в проекте.

конкретные идеи

Подготовка основной информации

Код фронтенда реализует базовую статическую маршрутизацию, такую ​​как: маршрутизация страницы входа, маршрутизация страницы ошибки сервера и т. д. (здесь есть ямка, о которой будет сказано позже). В базе данных хранится вся информация о динамической маршрутизации.

Как база данных хранит информацию о динамической маршрутизации?

Решение, которое я выбрал, состоит в том, чтобы сначала преобразовать объект, на который ссылается маршрут, а затем преобразовать список маршрутов вJSONФормат для передачи в тыл, после хранения в базе данных внутренней обработки. Таким образом, он передается на переднюю и заднюю частьJSONИнформация о списке маршрутов в формате.

Как упорядочить объекты, на которые есть ссылки в маршрутах?

Настоящая проблема, с которой я сталкиваюсь: использованиеUIКомпонент предоставляет схему макета и должен ссылаться на компонент макета и ссылаться на конкретную страницу в дочернем маршруте.

Решение, которое я выбрал, таково: относиться к компонентам макета, на которые нужно ссылаться, по-разному.componentсвойств, используйте короткие строки вместо компонентов макета и используйте строки пути к файлу вместо импорта страниц.

Конкретную реализацию можно увидеть в следующем примере кода.

Используйте глобальную переднюю защиту для оценки информации о маршрутизации

1-判断用户是否登录
    1.1-若未登录,跳转至登录页面
    1.2-若已经登录,判断是否已获取路由列表
        1.2.1-若未获取,从后端获取、解析并保存到 `Vuex` 中
        1.2.2-若已获取,跳转至目标页面

Я не проводил здесь особых исследований, я напрямую сохранял полученные данные вVuexВ процессе реального применения проекта следует учитывать безопасность хранения данных.

Как реализовать парсинг списка маршрутов?

  1. БудуJSONИнформация о маршрутизации в формате анализируется какJavaScriptобъект списка;
  2. использование объектов спискаfilterметод реализует аналитическую функцию черезcomponentОпределите, является ли это компонентом макета;
  3. Если это компонент макета, используйте вместо него компонент макета.componentнить;
  4. Для конкретной страницы используйтеloadViewФункция загружает соответствующую конкретную страницу;

Используйте метод Mar Router.addrotes для динамического добавления маршрутизации

Этот шаг очень прост, передайте проанализированный список маршрутов черезrouter.addRoutesСпособ добавлен кRouterв примере.

Простой код реализации

// router/index.js
import Vue from 'vue'
import store from '@/store'
import Router from 'vue-router'
import { getToken } from '@/lib/util'

Vue.use(Router)

// 定义静态路由
const staticRoutes = [
  {
    path: '/login',
    name: 'login',
    meta: {
      title: '登录页面',
      hideInMenu: true
    },
    component: () => import('@/view/login/login.vue')
  },
  {
    path: '/401',
    name: 'error_401',
    meta: {
      hideInMenu: true
    },
    component: () => import('@/view/error-page/401.vue')
  },
  {
    path: '/500',
    name: 'error_500',
    meta: {
      hideInMenu: true
    },
    component: () => import('@/view/error-page/500.vue')
  }
]

// 定义登录页面名称(为了方便理解才定义的)
const LOGIN_PAGE_NAME = 'login'

// 实例化 Router 对象
const router = new Router({
  routes: staticRoutes,
  mode: 'history'
})

// 定义全局前置守卫(里面有两个坑要注意)
router.beforeEach((to, from, next) => {
  // 通过自定义方法获取用户 token 用来判断用户登录状态
  const token = getToken()
  if (!token && to.name !== LOGIN_PAGE_NAME) {
    // 如果没有登录而且前往的页面不是登录页面,跳转到登录页
    next({ name: LOGIN_PAGE_NAME })
  } else if (!token && to.name === LOGIN_PAGE_NAME) {
    // 如果没有登录而且前往的页面是登录页面,跳转到登录页面
    // 这里有一个坑,一定要注意这一步和上一步得分开写
    // 如果把前两步判断合并为 if (!token) next({ name:login })
    // 则会形成登录页面无限刷新的错误,具体成因后面解释
    next()
  } else {
    // 如果登录了
    if (!store.state.app.hasGetRoute) {
      // 如果没有获取路由信息,先获取路由信息而后跳转
      store.dispatch('getRouteList').then(() => {
        router.addRoutes(store.state.app.routeList)
        // 这里也是一个坑,不能使用简单的 next()
        // 如果直接使用 next() 刷新后会一直白屏
        next({ ...to, replace: true })
      })
    } else {
      // 如果已经获取路由信息,直接跳转
      next()
    }
  }
})

export default router
// store/index.js
import router from '@/router'
import Main from '@/components/main'
import { getToken } from '@/lib/util'
import { getRoute } from '@/api/app'

const loadView = (viewPath) => {
  // 用字符串模板实现动态 import 从而实现路由懒加载
  return () => import(`@/view/${viewPath}`)
}

const filterAsyncRouter = (routeList) => {
  return routeList.filter((route) => {
    if (route.component) {
      if (route.component === 'Main') {
        // 如果 component = Main 说明是布局组件
        // 将真正的布局组件赋值给它
        route.component = Main
      } else {
        // 如果不是布局组件就只能是页面的引用了
        // 利用懒加载函数将实际页面赋值给它
        route.component = loadView(route.component)
      }
      // 判断是否存在子路由,并递归调用自己
      if (route.children && route.children.length) {
        route.children = filterAsyncRouter(route.children)
      }
      return true
    }
  })
}

export default {
  state: {
    routeList: [],
    token: getToken(),
    hasGetRoute: false
  },
  mutations: {
    setRouteList(state, data) {
      // 先将 JSON 格式的路由列表解析为 JavaScript List
      // 再用路由解析函数解析 List 为真正的路由列表
      state.routeList = filterAsyncRouter(JSON.parse(data))
      // 修改路由获取状态
      state.hasGetRoute = true
    }
  },
  atcions: {
    getRouteList({ state, commit }) {
      return new Promise((resolve) => {
        const token = state.token
        getRoute({ token }).then((res) => {
          let data = res.data.data
          // 注意这里取出的是 JSON 格式的路由列表
          commit('setRouteList', data)
          resolve()
        })
      })
    }
  }
}

Общая проблема

Страница зависла на странице входа и продолжает обновляться

Решение этой проблемы было упомянуто в «коде реализации», просто будьте осторожны, чтобы не перепутать два незарегистрированных состояния при оценке состояния входа в систему. Но это временное решение, потому что одна и та же проблема может быть вызвана разными формами кода.В чем причина проблемы? Затем медленно анализируем:

Давайте сначала предположим, что два незарегистрированных состояния случайно смешаны вместе, чтобы судить:

if (!token) {
  next({ name: LOGIN_PAGE_NAME })
}

здесьnext({ name: LOGIN_PAGE_NAME })Этот метод снова активирует глобальную переднюю защиту, что приводит к еще одному решению о входе и срабатываниюnext({ name: LOGIN_PAGE_NAME }), если этот рекурсивный вызов продолжится, страница будет зависать и постоянно обновляться.

Динамическая маршрутизация с отложенной загрузкой маршрутизации

Схема для достижения этого также показана в примере кода:

const loadView = (viewPath) => {
  return () => import(`@/view/${viewPath}`)
}

Вот функция, которая обычно не используется в JavaScript: шаблоны строк, используйте эту функцию для создания строк, которые не поддерживают конкатенацию строк.importДействия могут быть динамичными.importразные модули.

404 после динамического обновления маршрута

Это должно быть одной из самых распространенных ошибок в этом решении.Первоначальный замысел состоит в том, что многие люди добавляют маршрут страницы 404 при создании «базового статического маршрута», чтобы динамический маршрут на начальном этапе загрузки страницы не В экземпляре маршрутизации появится страница 404 с самым широким диапазоном совпадений. Решение состоит в том, чтобы добавить маршрутизацию страницы 404 в динамическую маршрутизацию.

Пустая страница после обновления динамической маршрутизации

Есть много причин для этой проблемы, проблема, с которой я столкнулся, заключается в использованииСправочная статья 3Это решено, но я еще не понял конкретного принципа, и я обновлю его, когда проведу какое-то исследование.

Заголовок нестабилен при обновлении страницы динамической маршрутизации

Причина этой проблемы проста: поскольку информация о маршрутизации не была загружена при обновлении страницы, информация о заголовке вообще не загружается. Но я не нашел лучшего решения, и я обновлю его после изучения.

Ссылаться на

  1. Большой Брат: реализация динамической маршрутизации Vue...
  2. Страница документации Vue Router
  3. rambo: динамическая маршрутизация vue router становится пустой страницей после обновления