深入 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: 工程化工具层

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

相关推荐
子兮曰2 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰2 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万2 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝2 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
三十而立洋3 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁3 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
汉堡大王95273 天前
Jev:不是聊天机器人, 而是一个智能 if 语句
前端·人工智能·后端
梦想很大很大3 天前
从运行事实到回归证据:Workrun 的 Telemetry 与 Evaluation 实践
前端·人工智能·后端
计算机魔术师3 天前
Meta Muse agent 接入 Shopify 的 Shop Pay 实现代理式购物
前端
沙蒿同学3 天前
我用 Go 搭了一条 AI Agent 流水线:从 1 张商品图到一整套淘宝详情页
前端·javascript·后端