深入 Lyt.js 路由系统:L6 生态系统层的核心

深入 Lyt.js 路由系统:L6 生态系统层的核心

基于 Lyt.js v6.6.0 @lytjs/router 和 @lytjs/router-fs 包源码,深入解析路由系统的设计理念、导航守卫、路由匹配和文件系统路由。

一、路由系统架构

在 Lyt.js v6.6.0 的 8 层架构中,路由系统位于 L6 生态系统层:

makefile 复制代码
L5: 组件基础层
L4: 插件与适配层
L3: 核心运行时层
L2: 渲染引擎层
L1: 核心原语层
  ↓
L6: 生态系统层
  ├── @lytjs/router (路由系统)
  ├── @lytjs/router-fs (文件系统路由)
  ├── @lytjs/api (API 路由)
  ├── @lytjs/store (状态管理)
  ├── @lytjs/ui (UI 组件库)
  └── ...

二、快速开始

typescript 复制代码
import { createApp } from '@lytjs/core'
import { createRouter, createWebHistory } from '@lytjs/router'
import Home from './views/Home.lyt'
import About from './views/About.lyt'
import User from './views/User.lyt'

const router = createRouter({
  mode: 'history',
  routes: [
    { path: '/', component: Home },
    { path: '/about', component: About },
    { path: '/user/:id', component: User },
  ]
})

const app = createApp(App)
app.use(router)
app.mount('#app')

三、路由模式

Lyt.js 支持两种路由模式:

3.1 History 模式

使用 HTML5 History API,适合有服务器配置的场景:

typescript 复制代码
import { createWebHistory } from '@lytjs/router'

const router = createRouter({
  mode: 'history',
  history: createWebHistory('/app'),
  routes: [...]
})

特点:

  • URL 更加美观(/user/123)
  • 需要服务器配置处理 404
  • 支持 history.pushState 和 history.replaceState
3.2 Hash 模式

使用 URL hash(#),无需服务器配置:

typescript 复制代码
import { createHashHistory } from '@lytjs/router'

const router = createRouter({
  mode: 'hash',
  routes: [...]
})

特点:

  • 无需服务器配置
  • URL 包含 #(/#/user/123)
  • 适合静态托管环境

四、路由定义

4.1 基础路由
typescript 复制代码
const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About },
  { path: '/contact', component: Contact },
]
4.2 动态路由
typescript 复制代码
const routes = [
  { path: '/user/:id', component: User },
  { path: '/post/:category/:slug', component: Post },
  { path: '/order/:id?', component: Order }, // 可选参数
]
4.3 嵌套路由
typescript 复制代码
const routes = [
  {
    path: '/user/:id',
    component: UserLayout,
    children: [
      { path: '', component: UserProfile },
      { path: 'posts', component: UserPosts },
      { path: 'settings', component: UserSettings },
    ]
  }
]
4.4 命名路由
typescript 复制代码
const routes = [
  {
    path: '/user/:id',
    name: 'user',
    component: User
  }
]

// 编程式导航
router.push({ name: 'user', params: { id: '123' } })
4.5 别名路由
typescript 复制代码
const routes = [
  { path: '/home', component: Home, alias: '/' }
]

五、路由参数

5.1 组件中获取参数
typescript 复制代码
// 方式一:通过 inject
import { useRoute } from '@lytjs/router'

const route = useRoute()
console.log(route.params.id)    // URL 参数
console.log(route.query.search) // 查询参数
console.log(route.hash)         // hash 值

// 方式二:通过 $route
defineComponent({
  template: '<p>User ID: {{ $route.params.id }}</p>'
})
5.2 参数变化监听
typescript 复制代码
const route = useRoute()

// 监听参数变化
watch(
  () => route.params.id,
  (newId, oldId) => {
    console.log(`ID 从 ${oldId} 变为 ${newId}`)
    // 重新获取数据
  }
)

六、导航守卫

6.1 全局前置守卫
typescript 复制代码
router.beforeEach((to, from, next) => {
  // to: 目标路由
  // from: 当前路由
  // next: 继续导航的函数
  
  if (to.meta.requiresAuth && !isLoggedIn()) {
    next('/login')
  } else {
    next()
  }
})
6.2 全局解析守卫
typescript 复制代码
router.beforeResolve((to, from, next) => {
  // 在导航被确认前,所有组件内守卫和异步路由组件被解析之后调用
  // 适合做数据预获取
  fetchData(to.params.id).then(data => {
    to.meta.data = data
    next()
  })
})
6.3 全局后置钩子
typescript 复制代码
router.afterEach((to, from) => {
  // 导航确认后调用
  document.title = to.meta.title || 'Lyt.js App'
  analytics.pageView(to.path)
})
6.4 路由独享守卫
typescript 复制代码
const routes = [
  {
    path: '/admin',
    component: Admin,
    beforeEnter: (to, from, next) => {
      if (isAdmin()) {
        next()
      } else {
        next('/403')
      }
    }
  }
]
6.5 组件内守卫
typescript 复制代码
defineComponent({
  beforeRouteEnter(to, from, next) {
    // 在渲染该组件的对应路由被确认前调用
    // 不能访问 this
    next(vm => {
      // 通过 vm 访问组件实例
    })
  },
  
  beforeRouteUpdate(to, from, next) {
    // 在当前路由改变,但该组件被复用时调用
    // 适合处理参数变化
  },
  
  beforeRouteLeave(to, from, next) {
    // 导航离开该组件的对应路由时调用
    // 可以访问 this
    if (hasUnsavedChanges()) {
      const answer = confirm('有未保存的更改,确定离开吗?')
      if (answer) {
        next()
      } else {
        next(false)
      }
    } else {
      next()
    }
  }
})
6.7 导航守卫执行顺序
  1. 导航触发
  2. 失活的组件调用 beforeRouteLeave
  3. 全局 beforeEach
  4. 复用组件调用 beforeRouteUpdate
  5. 路由独享 beforeEnter
  6. 解析异步路由组件
  7. 激活组件调用 beforeRouteEnter
  8. 全局 beforeResolve
  9. 导航确认
  10. 全局 afterEach

七、编程式导航

7.1 基础导航
typescript 复制代码
// 字符串路径
router.push('/user/123')

// 对象路径
router.push({ path: '/user/123' })

// 命名路由
router.push({ name: 'user', params: { id: '123' } })

// 带查询参数
router.push({ path: '/search', query: { q: 'vue' } })

// 替换当前记录
router.replace('/home')

// 前进/后退
router.go(1)   // 前进
router.go(-1)  // 后退
router.back()  // 后退
router.forward() // 前进
7.2 导航控制
typescript 复制代码
// 取消导航
router.beforeEach((to, from, next) => {
  if (needsGuard(to)) {
    next(false) // 取消导航
  } else {
    next()
  }
})

// 重定向
router.beforeEach((to, from, next) => {
  if (to.path === '/old') {
    next('/new')
  } else {
    next()
  }
})

// 导航错误
router.onError(error => {
  console.error('导航错误:', error)
})

八、元信息(Meta)

8.1 定义 Meta
typescript 复制代码
const routes = [
  {
    path: '/admin',
    component: Admin,
    meta: {
      requiresAuth: true,
      role: 'admin',
      title: '管理后台'
    }
  }
]
8.2 访问 Meta
typescript 复制代码
router.beforeEach((to, from, next) => {
  if (to.meta.requiresAuth) {
    // 需要认证
  }
  if (to.meta.role === 'admin') {
    // 需要管理员权限
  }
  next()
})

九、路由懒加载

9.1 箭头函数
typescript 复制代码
const routes = [
  { path: '/home', component: () => import('./views/Home.vue') },
  { 
    path: '/about', 
    component: () => import('./views/About.vue')
      .then(m => m.default) // 支持 Promise
  }
]
9.2 路由懒加载 + Loading
typescript 复制代码
import { defineAsyncComponent } from '@lytjs/core'

const routes = [
  {
    path: '/dashboard',
    component: defineAsyncComponent({
      loader: () => import('./views/Dashboard.vue'),
      loadingComponent: LoadingSpinner,
      errorComponent: ErrorBoundary,
      delay: 200,
      timeout: 3000
    })
  }
]
9.3 路由分组
typescript 复制代码
// 将某个路由下的所有组件都打包在同一个异步块中
const routes = [
  {
    path: '/admin',
    component: AdminLayout,
    children: [
      { path: 'users', component: () => import('./views/AdminUsers.vue') },
      { path: 'settings', component: () => import('./views/AdminSettings.vue') }
    ]
  }
]

十、过渡动画

typescript 复制代码
// 路由过渡
defineComponent({
  template: `
    <Transition name="fade" mode="out-in">
      <router-view />
    </Transition>
  `
})

// CSS
.fade-enter-active,
.fade-leave-active {
  transition: opacity 0.3s ease;
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}

十一、路由类型安全

Lyt.js 支持 TypeScript 类型推导:

typescript 复制代码
import type { RouteRecordRaw } from '@lytjs/router'

const routes: RouteRecordRaw[] = [
  {
    path: '/user/:id',
    name: 'User',
    component: () => import('./views/User.vue'),
    props: true, // 将路由参数作为 props 传递给组件
    children: [
      {
        path: 'posts',
        component: () => import('./views/UserPosts.vue')
      }
    ]
  }
]

// 组件中使用
defineComponent({
  props: {
    id: String // 从路由参数自动获取
  },
  setup(props) {
    // props.id 已有类型
  }
})

十二、文件系统路由

Lyt.js v6.6.0 提供了 @lytjs/router-fs 包,支持基于文件系统的路由:

bash 复制代码
src/
└── pages/
    ├── index.lyt          → /
    ├── about.lyt          → /about
    ├── user/
    │   ├── index.lyt     → /user
    │   └── [id].lyt      → /user/:id
    └── blog/
        ├── index.lyt      → /blog
        └── [slug].lyt    → /blog/:slug
typescript 复制代码
import { createFileSystemRouter } from '@lytjs/router-fs'

const router = createFileSystemRouter('./src/pages', {
  extensions: ['.lyt', '.vue'],
  // 导入模式
  importMode: 'async', // 'sync' | 'async' | (path) => Promise
  // 路由选项
  routes: {
    index: { name: 'home' },
    dynamic: { prefix: '[' }
  }
})

十三、在 v6.6.0 中的位置

路由系统在 8 层架构中的位置:

bash 复制代码
L1: 核心原语层
  ├── @lytjs/reactivity
  ├── @lytjs/vdom
  └── @lytjs/compiler
L2: 渲染引擎层
  ├── @lytjs/renderer
  ├── @lytjs/component
  └── @lytjs/dom-runtime
L3: 核心运行时层
  └── @lytjs/core
L4: 插件与适配层
  ├── @lytjs/plugin-auth (权限插件)
  └── ...
L5: 组件基础层
L6: 生态系统层 ← 当前层
  ├── @lytjs/router
  ├── @lytjs/router-fs
  ├── @lytjs/store
  └── ...
L7: 工程化工具层

路由系统依赖核心运行时层,同时被插件层(如权限插件)扩展。

相关推荐
程序员Sunday2 小时前
JavaScript 深拷贝和浅拷贝有什么区别?structuredClone 能替代 JSON 拷贝吗?
前端·javascript
ShineWinsu3 小时前
对于CSS:选择器的解析
前端·css·面试·html·web·选择器·网页
m0_587383003 小时前
碰碰好评卡功能落地实战 从需求梳理到上线部署全流程实操指南
java·linux·服务器·前端·javascript·vue.js·人工智能
Pu_Nine_93 小时前
Vue‑Flow 从零入门实战|AI‑Agent 拓扑图开发
前端·javascript·vue.js
keyipatience3 小时前
CSS 学习(1):语法、引入方式、选择器、字体与背景
前端·css·html
程序人生8883 小时前
本地向量底座怎么搭?DocConverter Web 的 BGE 嵌入模型、ChromaDB 与外部 Milvus 接入
前端·milvus
恋猫de小郭3 小时前
Flutter Android 改动:APK 不再允许通过 Intent 动态修改 Engine 参数
android·前端·flutter
ck0135793 小时前
视频转 GIF 的基本流程与文件大小优化
前端·测试工具·html·音视频·视频
郝学胜-神的一滴3 小时前
Web安全入门:读懂Web世界里的攻防
前端·网络·后端·安全·web安全·hibernate
Amos_Web3 小时前
Rspack 源码解析(二十四):AssetPlugin 如何让图片同时是「URL 字符串」和「真实文件」
前端·rust·前端框架