百度视频播放器安卓版(百搜视频)
171.93MB · 2025-11-02
在 Vue 应用开发中,我们经常需要围绕 Vue Router 开发各种功能,比如页面导航方向、跨页面通信、滚动位置还原等。这些功能本可以作为 Vue Router 的扩展独立开发,但由于 Vue Router 官方并不支持插件机制,我们不得不将它们作为 Vue 插件来实现,这带来了以下问题:
以页面缓存插件为例,它本应为 Vue Router 提供功能,却必须作为 Vue 插件开发,这让人感觉关注点有所偏离:
import type { ComputedRef, Plugin } from 'vue'
declare module 'vue-router' {
interface Router {
keepAlive: {
pages: ComputedRef<string[]>
add: (page: string) => void
remove: (page: string) => void
}
}
}
export const KeepAlivePlugin: Plugin = (app) => {
const router = app.config.globalProperties.$router
if (!router) {
throw new Error('[KeepAlivePlugin] 请先安装 Vue Router.')
}
const keepAlivePageSet = shallowReactive(new Set<string>())
const keepAlivePages = computed(() => Array.from(keepAlivePageSet))
router.keepAlive = {
pages: keepAlivePages,
add: (page: string) => keepAlivePageSet.add(page),
remove: (page: string) => keepAlivePageSet.delete(page),
}
// 在路由变化时自动更新缓存列表
router.afterEach((to, from) => {
if (to.meta.keepAlive) {
keepAlivePageSet.add(to.fullPath)
}
})
}
仍以页面缓存插件为例,我们需要使用 effectScope 创建响应式副作用,并在应用卸载时手动停止:
import { effectScope } from 'vue'
// ...
export const KeepAlivePlugin: Plugin = (app) => {
// ...
const scope = effectScope(true)
const keepAlivePageSet = scope.run(() => shallowReactive(new Set<string>()))!
const keepAlivePages = scope.run(() =>
computed(() => Array.from(keepAlivePageSet)),
)!
// ...
app.onUnmount(() => {
scope.stop()
keepAlivePageSet.clear()
})
}
Vue Router 的 createRouter() 和 app.use(router) 是分离的,无法在创建 Router 时立即安装扩展插件,这可能导致插件功能在初始化之前就被调用:
// src/router/index.ts
export const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/home',
component: HomeView,
},
],
})
// KeepAlivePlugin 的类型扩展已生效,但插件可能尚未初始化
// 手动调用插件方法
router.keepAlive.add('/home')
// main.ts
app.use(router).use(KeepAlivePlugin)
经过 Vue Router 4 插件集合与 Naive UI Pro 插件系统的设计实践,我开发了 vue-router-plugin-system,旨在为 Vue Router 提供标准化的插件系统与统一的安装机制,让路由扩展功能的开发和集成变得简单、高效、可复用。
仍以页面缓存插件为例,使用 vue-router-plugin-system 后的完整代码如下:
// src/router/plugins/keep-alive.ts
import type { ComputedRef, Plugin } from 'vue'
import type { RouterPlugin } from 'vue-router-plugin-system'
import { withInstall } from 'vue-router-plugin-system'
declare module 'vue-router' {
interface Router {
keepAlive: {
pages: ComputedRef<string[]>
add: (page: string) => void
remove: (page: string) => void
}
}
}
// RouterPlugin 在插件安装时会通过 effectScope 自动收集响应式副作用,
// 在应用卸载时自动停止,且 router 实例会被显式地注入到插件上下文中,
// 无需再通过 app.config.globalProperties.$router 获取
export const KeepAlivePluginImpl: RouterPlugin = ({ router, onUninstall }) => {
const keepAlivePageSet = shallowReactive(new Set<string>())
const keepAlivePages = computed(() => Array.from(keepAlivePageSet))
router.keepAlive = {
pages: keepAlivePages,
add: (page: string) => keepAlivePageSet.add(page),
remove: (page: string) => keepAlivePageSet.delete(page),
}
// 在路由变化时自动更新缓存列表
router.afterEach((to, from) => {
if (to.meta.keepAlive) {
keepAlivePageSet.add(to.fullPath)
}
})
onUninstall(() => {
keepAlivePageSet.clear()
})
}
// src/router/index.ts
import { createRouter } from 'vue-router-plugin-system'
import { KeepAlivePluginImpl } from './plugins/keep-alive'
// 使用库提供的 createRouter 函数创建 Router 实例,
// 支持直接注册插件,也支持其他集成方式(详见下文)
export const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/home',
component: HomeView,
},
],
// 通过 plugins 选项在创建 Router 时自动安装
plugins: [KeepAlivePluginImpl],
})
// 插件功能已就绪,可以安全调用
router.keepAlive.add('/home')
一个完整的插件示例:
import type { RouterPlugin } from 'vue-router-plugin-system'
import { inject, watch } from 'vue'
const LoggerPlugin: RouterPlugin = ({
router,
runWithAppContext,
onUninstall,
}) => {
// 添加路由守卫
router.beforeEach((to, from, next) => {
console.log(`路由跳转: ${from.path} → ${to.path}`)
next()
})
// 需要 App 上下文时使用(如 inject、pinia store 等)
runWithAppContext(() => {
const theme = inject('theme', 'light')
watch(router.currentRoute, (route) => {
console.log('当前路由:', route.path, '主题:', theme)
})
})
// 注册清理逻辑
onUninstall(() => {
console.log('插件正在清理')
})
}
更多实用插件示例可查阅 Vue Router 4 插件集合。
// 将此包作为开发依赖,用 withInstall 包装插件并打包到 dist 中
import { withInstall } from 'vue-router-plugin-system'
const MyRouterPlugin = withInstall(
({ router, runWithAppContext, onUninstall }) => {
// 插件实现
},
)
export default MyRouterPlugin
// package.json
{
"devDependencies": {
"vue-router-plugin-system": "latest"
}
}
import MyRouterPlugin from 'some-plugin-package'
// 选项 A:直接安装到路由实例,推荐紧跟在 createRouter 之后调用
MyRouterPlugin.install(router)
// 选项 B:作为 Vue 插件注册,必须在 Vue Router 之后,否则会抛出异常
app.use(router)
app.use(MyRouterPlugin)
对于应用内部开发的路由插件,可以在应用侧统一注册和管理。
// 只需导出 RouterPlugin 实现
import type { RouterPlugin } from 'vue-router-plugin-system'
// src/router/plugins/auth.ts
export const AuthPlugin: RouterPlugin = ({
router,
runWithAppContext,
onUninstall,
}) => {
// 插件实现
router.beforeEach((to, from, next) => {
// 权限检查逻辑
next()
})
}
// src/router/plugins/cache.ts
export const CachePlugin: RouterPlugin = ({
router,
runWithAppContext,
onUninstall,
}) => {
// 缓存管理逻辑
}
使用 batchInstall
// router.ts
import { batchInstall } from 'vue-router-plugin-system'
import { AuthPlugin, CachePlugin } from './plugins'
const router = createRouter({
history: createWebHistory(),
routes: [],
})
// 紧跟在 createRouter 之后调用
batchInstall(router, [AuthPlugin, CachePlugin])
使用 createRouter
import { createWebHistory } from 'vue-router'
import { createRouter } from 'vue-router-plugin-system'
import { AuthPlugin, CachePlugin } from './plugins'
const router = createRouter({
history: createWebHistory(),
routes: [],
// 新增插件选项
plugins: [AuthPlugin, CachePlugin],
})
提供统一的 RouterPlugin 接口:
type RouterPlugin = (ctx: RouterPluginContext) => void
interface RouterPluginContext {
router: Router // Vue Router 实例
runWithAppContext: (handler: (app: App) => void) => void // 在 App 上下文中执行
onUninstall: (handler: () => void) => void // 注册清理回调
}
插件中创建的响应式副作用(watch、computed 等)会在卸载时自动清理,无需手动管理 effectScope。
createRouter(options) - 扩展版路由创建函数,支持 plugins 选项
withInstall(plugin) - 包装插件,支持 app.use() 和 Plugin.install(router) 两种安装方式
batchInstall(router, plugins) - 批量安装多个插件
interface RouterPluginContext {
router: Router // Vue Router 实例
runWithAppContext: (handler: (app: App) => void) => void // 在 App 上下文中执行
onUninstall: (handler: () => void) => void // 注册清理回调
}
router - 用于添加路由守卫、访问路由信息、编程式导航runWithAppContext - 当需要使用 inject()、pinia store 等 App 上下文 API 时使用onUninstall - 注册清理回调,在应用卸载时按顺序执行effectScope 中运行,响应式副作用自动清理install 只会被包装一次该插件化模式受 Naive UI Pro 项目启发,并在其基础上进行了扩展和完善。感谢 Zheng-Changfu 提供的宝贵思路和参考实现。
如果这套路由插件化方案对你有帮助,欢迎:
你的每一次 Star、反馈与分享,都是持续完善的动力。感谢支持!