vue-page-controller
v0.0.5-beta7
Published
**解决问题** * 页面前进(暂存、创建)、后退(销毁、复用)、替换时,组件实例能按栈数据结构做创建、销毁 * keep-alive 组件复用为堆数据结构,且只能按组件复用 * vue-router 页面之间无法传递对象及函数参数
Downloads
3
Readme
page-controller
解决问题
- 页面前进(暂存、创建)、后退(销毁、复用)、替换时,组件实例能按栈数据结构做创建、销毁
- keep-alive 组件复用为堆数据结构,且只能按组件复用
- vue-router 页面之间无法传递对象及函数参数
注意事项
- 仅支持vue3
- 路由功能相比vue-router,不支持正则匹配、别名, 不支持路由嵌套
数据结构说明
页面配置
页面路由定义时配置信息
type PageConfig = {
// 页面名称
name: string
// 页面显示路径
path: string
// 页面重定向
redirect?: PageRedirect
// 页面组件
component?: Component | DefineComponent | Promise<Component | DefineComponent>
// 页面其他信息
meta?: Record<string, any>
}
页面信息
页面加载或路由钩子方法
type PageInfo<T = Record<any, any>> = {
name: string
path: string
// query参数在hash模式会显示在url中
query: Record<string, string | undefined>
// 任意类型
params?: T
}
页面路由钩子
interface PageHooks {
/**
* 页面创建之前,没有页面实例
*/
beforePageEnter?: OptionConfig<BeforePageEnterOption>
/**
* 页面移除之前,有页面实例
*/
beforePageLeave?: OptionConfig<BeforePageLeaveOption>
/**
* 页面进入后台之前,有页面实例
*/
beforePageBackend?: OptionConfig<BeforePageBackendOption>
/**
* 页面进入前台之前,有页面实例(hash模式,当页面刷新后,再做后退操作时,会执行beforePageEnter钩子)
*/
beforePageFrontend?: OptionConfig<BeforePageFrontendOption>
/**
* 页面改变触发事件
* @param params
*/
onPageChange?: (
params: OptionConfigParams & {
type: PageActionType
}
) => void
}
页面控制模式
页面路由控制的两种模式,Hash模式渲染页面和浏览器的记录会双向关联;Memory模式,只会在当前内存保存,页面刷新路由状态丢失
enum HistoryType {
// url hash模式
Hash,
// 内存模式
Memory
}
设计说明
就部分关键功能做说明
如何标记组件实例的唯一标识
当push、replace创建一条路由记录时,生成唯一标识保存到路由query参数中,以此作为当前路由及渲染组件实例的唯一标识
如何实现页面栈管理
此处分为了两部分:页面路由信息栈、组件实例栈
其中页面路由信息栈使用数组维护
为避免使用Vue3私有api,保证版本兼容性,使用keep-alive,通过动态生成组件,完成组件实例栈管理
此处利用keep-alive 的include参数控制哪些组件实例需要被缓存
根据路由信息栈发生改变时,生成 include 参数供 keep-alive 使用,同时根据栈顶路由信息动态生成对应组件,组件名称与 include 参数一致
如此可达到,页面路由信息栈、组件实例栈一致的目的
如何实现url hash 与渲染页面联动
路由控制器的方法(push、pop、replace)触发跳转时,通过浏览器 history 更新对应 status 记录(当前、之前、之后 页面标识)和
当前浏览器hash变化时,监听 popstate 事件,在 status 的当前页面标识和根据当前hash得到的页面标识不一致时,触发push、pop操作
如何实现hash模式页面刷新防参数丢失
url hash模式,路由变化时,使用sessionStorage保存页面路由信息栈的序列化信息,当页面控制器初始化时,首先加载sessionStorage反序列化后的信息
代码设计说明
渲染页面生命周期
- push 当前页面组件实例进入后台,根据路由信息创建组件入栈并激活
- pop 当前页面组件实例销毁出栈,栈顶页面组件实例再次激活
- replace 当前页面组件实例销毁出栈,根据路由信息创建组件入栈并激活
当url hash模式刷新浏览器
session 路由记录存在
- pop 当前页面组件出栈,无法找到栈顶页面组件实例,只能根据栈顶页面信息重新创建
session 路由记录不存在
浏览器前进、后退及pop操作触发的页面 push、pop,均会转换为replace操作(可能为多步前进后退,无法维护页面栈状态)
如何使用
路由定义
import { createPageController } from 'vue-page-controller'
const pageController = createPageController({
// 可选参数, 路由query参数添加的key
pageIdKey: 'pid',
// 页面打开,默认加载的路由
defaultName: 'root',
// 路由定义
pageConfigs: [
{
name: 'root',
path: '/',
component: PageList
},
{
name: 'list',
path: '/list',
component: PageList
},
{
name: 'detail',
path: '/detail',
component: () => import('./components/Detail.vue')
}
]
})
当需要改变query参数中页面id的key,可自定义pageIdKey
参数
注意
当使用url hash模式时,需要在vue初始化时使用
createPageController
创建控制器,并使用app.use全局挂载。一个app最多只能有一个url hash模式的路由控制器
const app = createApp(App) app.use(pageController)
当使用Memory模式时需要在setup 函数中创建控制器
路由入口
页面控制器入口组件为 PageController
import { PageController } from 'vue-page-controller'
- url hash模式使用全局配置控制器,组件内无需传入,
另外
app.use(pageController)
会自动全局使用组件,页面内直接使用即可<page-controller />
- 内存模式时需要手动引用组件,同时创建路由控制器传入
import { PageController } from 'vue-page-controller' export default defineComponent({ components: { PageController } })
<page-controller :controller="pageController" />
路由跳转
push 打开新页面
路由跳转参数中name、path至少有其中一个
const { pageController } = usePageController() // 使用name pageController.push({ name: 'detail' }) // 使用path pageController.push({ path: '/detail' }) // 使用query或params参数,其区别,可看数据结构PageInfo中说明 pageController.push({ name: 'detail', params: { info: { title: 'xxx' }, callback: (res) => {} }, query: { name: 'xxx' } })
备注: url hash模式页面刷新,当前页面params参数中有函数等不可序列化的参数时,函数等内容会丢失(不可序列化内容无法保存)
pop 页面后退
const { pageController } = usePageController() // 路由页面实例出栈 pageController.pop() // 路由页面后退 pageController.back()
pop、back 方法区别:
- pop方法,在路由栈记录为1时,不做任何操作
- 当为内存模式时,back即为pop方法
- 当为url hash模式时,back为浏览器history的back方法
建议使用back方法做后退操作,避免session路由记录信息丢失时无法后退
replace 替换当前页面 方法名称变化,参数信息同push
转场动画
PageController 组件内置了转场动画参数 animation
,开启后内部会使用Transition
组件,
根据页面不同跳转方式,再页面跳转前使用不同的Transition
动态过渡参数,不同跳转方式参数名称如下:
- push:page-push
- pop:page-pop
- replace:page-replace
例如:
全局引入一下css样式,具体转场效果可按需调整,Transition转场样式
.page-push-enter-active,
.page-push-leave-active,
.page-pop-enter-active,
.page-pop-leave-active {
transition: all 300ms ease-in-out;
}
.page-replace-enter-active {
transition: all 300ms ease-out;
}
.page-replace-leave-active {
transition: all 300ms ease-in;
}
.page-push-enter-from {
opacity: 0.5;
transform: translate3d(100%, 0, 0);
}
.page-push-leave-to {
opacity: 0.5;
transform: translate3d(-100%, 0, 0);
}
.page-pop-enter-from {
opacity: 0.5;
transform: translate3d(-100%, 0, 0);
}
.page-pop-leave-to {
opacity: 0.5;
transform: translate3d(100%, 0, 0);
}
.page-replace-enter-from,
.page-replace-leave-to {
opacity: 0;
}
路由钩子
在页面跳转过程中,其触发时机如上图所示(均为页面B所涉及的钩子函数),共有5个钩子函数。
- beforePageEnter 页面组件创建
- beforePageLeave 页面组件销毁
- beforePageBackend 页面组件进入后台
- beforePageFrontend 页面组件进入前台
- onPageChange 只要页面发生切换即会触发,以上4个钩子函数触发时必然伴随该钩子触发
5个钩子函数均可为异步函数,异步函数等待时会阻塞当前跳转行为,若期间有其他路由跳转变栈顶页面,则等待结束当前跳转行为取消
onPageChange 仅做通知,不会影响当前路由的行为,其余4个钩子,均能阻断当前路由的行为(返回值为false)
全局钩子函数定义
通过创建的页面控制器设置
pageController.beforeEach({
async beforePageEnter(options: BeforePageEnterOption) {
const notBreak = options.to.params?.idx !== 2
return notBreak
},
beforePageBackend(options: BeforePageBackendOption) {},
beforePageFrontend(options: BeforePageFrontendOption) {},
beforePageLeave(options: BeforePageLeaveOption) {},
onPageChange(options: OnPageFrontendOption) {}
})
页面内钩子函数设置
选项式api
各钩子函数均可设置
export default defineComponent({ name: 'xxx', setup() { return {} }, beforePageEnter(options: BeforePageEnterOption) {}, beforePageBackend(options: BeforePageBackendOption) {}, beforePageFrontend(options: BeforePageFrontendOption) {}, beforePageLeave(options: BeforePageLeaveOption) {}, onPageChange(options: OnPageFrontendOption) {} })
组合式api
仅能设置除beforePageEnter之外的钩子函数
export default defineComponent({ name: 'xxx', setup() { const { usePageBeforeEach } = usePageController() usePageBeforeEach({ beforePageBackend: (options: BeforePageBackendOption) => {}, beforePageFrontend: (options: BeforePageFrontendOption) => {}, beforePageLeave: (options: BeforePageLeaveOption) => {}, onPageChange: (options: OnPageFrontendOption) => {} }) return {} }, })
备注
当url hash模式刷新浏览器,页面再做pop操作时,没有组件实例beforePageFrontend不会触发,而是重新生成组件实例,触发beforePageEnter
钩子函数执行优先级
- (beforePageLeave、beforePageBackend) > (beforePageEnter、beforePageFrontend) > onPageChange
- 组合式api > 选项式api > 全局设置钩子
- 同一类型 先设置 > 后设置
其他
具体使用示例可查看demo应用,如有功能bug请及时反馈