海南 网站制作,wordpress搬家简书,网站留言如何做的,个人网页制作模板三张目录
01: 前言
02: 通用组件#xff1a;trigger-menu 和 trigger-menu-item 构建方案分析
03: 通用组件#xff1a;构建 trigger-menu 和 trigger-menu-item
04: 前台业务下 H5 的应用场景
05: 通用组件#xff1a;transition-router-view 构建方案分析 与 虚拟任务栈…目录
01: 前言
02: 通用组件trigger-menu 和 trigger-menu-item 构建方案分析
03: 通用组件构建 trigger-menu 和 trigger-menu-item
04: 前台业务下 H5 的应用场景
05: 通用组件transition-router-view 构建方案分析 与 虚拟任务栈
过渡动画
组件缓存
小结
06: 通用组件transition-router-view 构建方案之过渡动效
07: 通用组件处理过渡动效展示样式错误的问题
08: 通用组件虚拟任务栈处理
09: 通用组件记录页面滚动位置
10: 总结 01: 前言
移动端的应用应该以什么样的形式进行展示呢
它的展示形式如何区分浏览器端又为什么要进行区分
虚拟任务栈又是什么
02: 通用组件trigger-menu 和 trigger-menu-item 构建方案分析 这块内容充当了移动端中的 TabBar 的作用我们期望把它封装成一个通用的组件。
接下来我们就需要来分析一下这个“TabBar”我们把它叫做 trigger-menu 的构建方案。
我们期望将来 trigger-menu 可以以下面的形式进行使用
m-trigger-menuv-ifisMobileTerminalclassfixed bottom-6 m-auto left-0 right-0 w-[220px]
m-trigger-menu-itemiconhomeiconClassfill-zinc-900 dark:fill-zinc-200首页/m-trigger-menu-item……
/m-trigger-menu
也就是说它被分成了两个组件trigger-menu 和 trigger-menu-item。
其中 trigger-menu 表示整个的功能区域trigger-menu-item 表示其中的一项。
因此我们需要针对这两个组件分别进行分析 1. trigger-menu对于它而言只起到一个 包裹容器 的作用所以我们只需要提供一个对应的插槽即可。 2. trigger-menu-item起到了对应的展示作用展示包括了 icon 和 文字。所以内部应该存在 svg-icon 用来展示图片存在一个插槽用来展示文字。
到这里我们基本分析完成了这两个组件的构建方案整体还是比较简单的。
03: 通用组件构建 trigger-menu 和 trigger-menu-item
- src/libs
- - trigger-menu
- - - index.vue
- - trigger-menu-item
- - - index.vue
// src/libs/trigger-menu/index.vuetemplatedivclassmin-w-[180px] bg-white dark:bg-zinc-800 rounded-full shadow flex items-center justify-between px-2 py-1slot //div
/templatescript setup/script// src/libs/trigger-menu-item/index.vuetemplatedivclassw-5 flex flex-col items-center justify-center col mx-0.5clickonItemClickm-svg-icon:nameicon:fillClassiconClassclassw-2 h-2/m-svg-iconp classtext-sm mt-0.5 :classtextClassslot //p/div
/templatescript setup
import { useRouter } from vue-routerconst props defineProps({icon: {type: String,required: true},iconClass: {type: String},textClass: {type: String,default: text-zinc-900 dark:text-zinc-200},to: {type: String}
})const router useRouter()
const onItemClick () {if (!props.to) {return}router.push(props.to)
}
/scriptstyle langscss scoped/style使用组件
// src/views/main/index.vuem-trigger-menuv-ifisMobileTerminalclassfixed bottom-6 m-auto left-0 right-0 w-[220px]
m-trigger-menu-itemiconhomeiconClassfill-zinc-900 dark:fill-zinc-200首页/m-trigger-menu-itemm-trigger-menu-itemv-if$store.getters.tokeniconvipiconClassfill-zinc-400 dark:fill-zinc-500textClasstext-zinc-400 dark:text-zinc-500clickonVipClickVIP/m-trigger-menu-itemm-trigger-menu-itemiconprofileiconClassfill-zinc-400 dark:fill-zinc-500textClasstext-zinc-400 dark:text-zinc-500clickonMyClick{{ $store.getters.token ? 我的 : 登录 }}/m-trigger-menu-item
/m-trigger-menu
04: 前台业务下 H5 的应用场景
通常情况下我们说起移动端项目指的一般是两种 1. 原生 APP 2. H5 网页 此时我们所做的这个移动端指的就是 H5 网页。该内容依然是以网页为主但是被运行到手机端之中。
H5 网页应用到手机端的时候通常也是有两种运行的形式 1. 直接在手机端浏览器中运行。这种使用情况相对较少。在这种情况下用户明显的知道这就是一个网页。 2. 在原生组件 WebView 中运行混合开发。通常会被嵌入到 APP 之中。这种使用情况比较多以下内容主要针对此种情况进行说明。 这种情况下用户会认为该内容是 APP 的一部分不会把它当成网页。而是会把它当做 原生APP。一旦用户把它作为 APP 进行衡量就会对应用有更高的要求。 路由之间的跳转应该具备对应的动画并且上一个页面的状态应该被缓存页面的滚动状态和数据视图。想要实现这样的功能我们必须使用到之前提到过的 过渡动效。 我们期望把整个的一套移动端的跳转全部封装为一个 通用组件期望通过这个通用组件来实现 移动端下 H5 页面的过渡功能。
05: 通用组件transition-router-view 构建方案分析 与 虚拟任务栈 根据上一小节的分析可知我们接下来要实现 移动端的过渡动效以达到一个良好的移动端用户交互体验。 接下来尝试分析一下它的实现方案。
它的实现方案整体分为两种 1. 过渡动画。 2. 组件缓存。
过渡动画 想要实现这个功能我们需要使用到 过渡动效 这个功能它描述了两个路由之间进行过渡时的动画效果。在这个功能的官方描述中主要包含了三个对应的组件
!-- 路由出口 --
router-view v-slot{ Component }!-- 动画 --transition namefade!-- 动态组件 --component :isComponent //transition
/router-view
使用其中的 transition 就可以实现跳转时的动画效果。
大家需要注意过渡动画分为两部分 1. 进入动画。 2. 退出动画。
这里 transition 的 name 需要是动态的以此来表示对应的两种动画形式。
组件缓存
因为同时我们要使用到 组件缓存所以我们还需要依赖 keep-alive
这四个组件想要在一起工作将要按照以下的方式进行组合
!-- 路由出口 --
router-view v-slot{ Component }!-- 动画组件 --transition nametransitionName!-- 缓存组件 --keep-alive!-- 动态组件 --component :isComponent :key$route.fullPath /// 同域名下的跳转。比如动态路由 /detail/:id/keep-alive/transition
/router-view
有一点大家需要注意不是所有的组件都需要缓存。
我们把组件的进入和退出流程比作一个栈。
只有进入到栈中的组件才需要被缓存就像 Android 中的 任务栈 概念一样如下图所示 在当前咱们移动端的组件处理中我们同样期望有一个这样的栈来维护我们的组件进入和退出流程。我们把这样的一套流程称作虚拟任务栈。
对于这样的一个虚拟任务栈而言我们可以通过 数组 进行维护。因为数组与栈的概念有相似之处即先进后出 的流程。
我们可以通过 keep-alive 中的 include 概念把 虚拟任务栈 - 数组 进行绑定从而实现 任务栈 的缓存概念。
小结
本小节我们分析了接下来要去处理的移动端页面跳转功能。想要实现这样的功能主要分成了两大步 1. 过渡动画使用 过渡动效 实现。 2. 组件缓存虚拟任务栈 - 数组 配合 keep-alive 中的 include 实现。
06: 通用组件transition-router-view 构建方案之过渡动效
- src/libs
- - transition-router-view
- - - index.vue
// src/libs/transition-router-view/index.vuetemplate!-- 路由出口 --router-view v-slot{ Component }!-- 动画组件 --transition:nametransitionNamebefore-enterbeforeEnterafter-leaveafterLeave!-- 缓存组件 --keep-alive :includevirtualTaskStackcomponent:isComponent:class{ fixed top-0 left-0 w-screen z-50: isAnimation }:key$route.fullPath//keep-alive/transition/router-view
/templatescript
import { ref } from vue
import { useRouter } from vue-router// 无需监听路由的各种状态在 PC 端下
const NONE none
// 路由进入
const PUSH push
// 路由退出
const BACK back
// 路由跳转的 enum
const ROUTER_TYPE_ENUM [NONE, PUSH, BACK]
/scriptscript setup
const props defineProps({// 路由跳转的类型对应 ROUTER_TYPE_ENUMrouterType: {type: String,default: NONE,validator(val) {const result ROUTER_TYPE_ENUM.includes(val)if (!result) {throw new Error(你的 routerType 必须是 ${ROUTER_TYPE_ENUM.join(、)} 中的一个)}return result}},// 首页的组件名称对应任务栈中的第一个组件mainComponentName: {type: String,required: true}
})// 任务栈
const virtualTaskStack ref([props.mainComponentName])const router useRouter()
// 跳转动画
const transitionName ref()
/*** 监听路由变化*/
router.beforeEach((to, from) {// 定义当前动画名称transitionName.value props.routerTypeif (props.routerType PUSH) {// 入栈virtualTaskStack.value.push(to.name)} else if (props.routerType BACK) {// 出栈virtualTaskStack.value.pop()}// 进入首页默认清空栈if (to.name props.mainComponentName) {clearTask()}
})// 处理动画状态变化
const isAnimation ref(false)
const beforeEnter () {isAnimation.value true
}
const afterLeave () {isAnimation.value false
}/*** 清空栈*/
const clearTask () {virtualTaskStack.value [props.mainComponentName]
}
/scriptstyle langscss scoped
// push页面时新页面的进入动画
.push-enter-active {animation-name: push-in;animation-duration: 0.4s;
}
// push页面时老页面的退出动画
.push-leave-active {animation-name: push-out;animation-duration: 0.4s;
}
// push页面时新页面的进入动画
keyframes push-in {0% {transform: translate(100%, 0);}100% {transform: translate(0, 0);}
}
// push页面时老页面的退出动画
keyframes push-out {0% {transform: translate(0, 0);}100% {transform: translate(-50%, 0);}
}// 后退页面时即将展示的页面动画
.back-enter-active {animation-name: back-in;animation-duration: 0.4s;
}
// 后退页面时后退的页面执行的动画
.back-leave-active {animation-name: back-out;animation-duration: 0.4s;
}
// 后退页面时即将展示的页面动画
keyframes back-in {0% {width: 100%;transform: translate(-100%, 0);}100% {width: 100%;transform: translate(0, 0);}
}
// 后退页面时后退的页面执行的动画
keyframes back-out {0% {width: 100%;transform: translate(0, 0);}100% {width: 100%;transform: translate(50%, 0);}
}
/style// src/store/modules/app.jsimport { ALL_CATEGORY_ITEM } from /constantsexport default {namespaced: true,state: () ({// 路由跳转类型routerType: none}),mutations: {/*** 修改 routerType*/changeRouterType(state, newType) {state.routerType newType}}
}// src/store/getters.jsimport { isMobileTerminal } from /utils/flexibleexport default {……// 路由跳转方式routerType: (state) {// 在 PC 端下永远为 noneif (!isMobileTerminal.value) {return none}return state.app.routerType}
}// src/App.vue 使用组件m-transition-router-viewmainComponentNamehome:routerType$store.getters.routerType
/m-transition-router-view
// 除了 libs 中组件包含的跳转、前往首页的跳转 之外其他的跳转进行修改store.commit(app/changeRouterType, push)
router.push(/login)store.commit(app/changeRouterType, back)
router.back()07: 通用组件处理过渡动效展示样式错误的问题
// src/libs/transition-router-view/index.vuetemplatetransitionbefore-enterbeforeEnterafter-leaveafterLeavecomponent:class{ fixed top-0 left-0 w-screen z-50: isAnimation }//transition
/template
script setup
// 处理动画状态变化
const isAnimation ref(false)
const beforeEnter () {isAnimation.value true
}
const afterLeave () {isAnimation.value false
}
/script08: 通用组件虚拟任务栈处理
目前路由的跳转动画已经执行成功下面来处理对应的组件缓存。
对于组件缓存而言我们将通过 keep-alive 构建一个虚拟任务栈。
// src/libs/transition-router-view/index.vuetemplatekeep-alive :includevirtualTaskStack/keep-alive/templatescript setup// 任务栈
const virtualTaskStack ref([props.mainComponentName])/*** 监听路由变化*/
router.beforeEach((to, from) {……if (props.routerType PUSH) {// 入栈virtualTaskStack.value.push(to.name)} else if (props.routerType BACK) {// 出栈virtualTaskStack.value.pop()}// 进入首页默认清空栈if (to.name props.mainComponentName) {clearTask()}
})/*** 清空栈*/
const clearTask () {virtualTaskStack.value [props.mainComponentName]
}
/script
// 注意 各个单文件组件 的命名script
export default {name: home
}
/script
特殊情况处理
强制在复用的视图之间进行过渡
情况从一个详情页跳转到另一个详情页/pins/:id。 两个页面对应一个组件缓存可能会出现问题跳转可能也会有问题。
解决component :key$route.fullPath /
09: 通用组件记录页面滚动位置
keep-alive 组件只能够帮助我们缓存组件但是不能够记录页面的滚动位置。
如果我们想要记录页面滚动位置的话需要在 通用组件外 单独处理。可以使用 useScroll 进行记录。
目前在当前应用中我们仅需要保存 home 页面的滚动位置即可。
// src/views/main/index.vuescript setup
import { useScroll } from vueuse/core/*** 记录页面滚动位置*/
const containerTarget ref(null)
const { y: containerTargetScrollY } useScroll(containerTarget)
// 被缓存的组件再次可见会回调 onActivated 方法
onActivated(() {if (!containerTarget.value) {return}containerTarget.value.scrollTop containerTargetScrollY.value
})
/script
10: 总结
到这里咱们的整个移动端路由切换就已经全部完成了本文章主要涉及到了两个通用组件的构建 1. trigger-menu trigger-menu-item 2. transition-router-view 1. 动画效果 2. 组件缓存 3. 滚动位置缓存