全局前置守卫
router.beforeEach
小满称呼:中间件
//所有跳转、后退都会走这个函数
router.beforeEach((to, form, next) => {
console.log(to, form);
next()
})
小满在这里做的是一个登录的校验,使用了组件库这里都不进行说明
小满在这里使用了一个@别名,在这里对这个进行一个解释
-
在vite.config.ts文件下,代码如下 export default defineConfig({ plugins:[vue(),vueJsx()], resolve:{ alias:{ '@':fileURLToPath(new URL('./src',import.meta.url)), } } })
-
这样的作用是对你的文件起了一个别名,此处的@的别名对应的是./src。从上面的路径中我们也可以看到
resolve.alias
在组件之间相互引用时,可能是下面这样的:
import Hello from '../src.components/Hello';
其中的路径是相对于当前页面的。 但是如果嵌套等更为复杂,那么写起来会比较麻烦。但是如果我们通过这样的配置:
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@pages': path.join(__dirname, "..", "src", "pages"),
"@components": path.join(__dirname, "..", "src", "components"),
// 注意: 静态资源通过src,不能这么设置。
// "@assets": path.join(__dirname, "..", "src", "assets"),
}
其中 vue$ 表示引入 vue,就可以像下面这么写:
import Vue from 'vue'
另外,对于 @pages 和 @components 我们就可以直接引用了,而省去了一大堆的复杂应用,另外通过 @可以消除歧义。如下所示:
import Hello from '@components/Hello';
import App from '@pages/App'
值得注意的时: 在 webpack.config.js 中我们不能使用…/ 以及./ 这种形式的路径方式,而是通过 path.join 和 __dirname 这种形式来表示路径,否则会报错。
另外: 在组件中,我们会引用一些静态文件,即 static 下的文件, 这时我们就不能用 alias 下的配置了,而必须使用一般的配置方式。
我没找到vite的,根据webpack触类旁通
const rules = reactive({
user:[
{
required:true,//证明是不是必填
message:"失败给提示信息",
type:"string",//类型
tiggle:"change"//触发的条件
}
]
})
每个守卫方法接收三个参数:
to: Route, 即将要进入的目标 路由对象;
from: Route,当前导航正要离开的路由;
next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。
案例 权限判断
const whileList = ['/']//白名单
router.beforeEach((to, from, next) => {
let token = localStorage.getItem('token')
//白名单 有值 或者登陆过存储了token信息可以跳转 否则就去登录页面
if (whileList.includes(to.path) || token) {
next()//next()是放行的意思
} else {
next({
path:'/'//回到登录界面
})
}
})
呃,这个使用组件库的过程不好写笔记,建议自己看看视频
全局后置守卫(内容较深,后续回来补笔记)
使用场景一般可以用来做 loadingBar
你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受
next
函数也不会改变导航本身:和前置路由守卫相比为什么没有next功能呢?那是因为前置路由守卫是看大门前面的,而后置路由守卫则是在大门的后面。前面的保安如果都放行进来了,那后面的保安还要再确认一遍就太过繁复也没有必要啦
router.afterEach((to,from)=>{
Vnode.component?.exposed?.endLoading()
})
loadingBar 组件
<template>
<div class="wraps">
<div ref="bar" class="bar"></div>
</div>
</template>
<script setup lang='ts'>
import { ref, onMounted } from 'vue'
let speed = ref<number>(1)//这里是通过TS的规范类型为数字number类型,以下类似
let bar = ref<HTMLElement>()
let timer = ref<number>(0)//默认为0
const startLoading = () => {//开始进度条
let dom = bar.value as HTMLElement;//因为有可能为undefined,所以我们使用as进行一个断言为HTMLElement
speed.value = 1//初始化speed的值
timer.value = window.requestAnimationFrame(function fn() {//requestAnimationFrame会将回流重绘收集起来只走一次,性能会更好。这里可以使用箭头函数,但我们选择使用function。回调函数只走一次,所以我们起了一个fn的名字拿去递归
if (speed.value < 90) {
speed.value += 1;
dom.style.width = speed.value + '%'
timer.value = window.requestAnimationFrame(fn)//递归
} else {
speed.value = 1;
window.cancelAnimationFrame(timer.value)
}
})
}
const endLoading = () => {//结束进度条
let dom = bar.value as HTMLElement;
setTimeout(() => {
window.requestAnimationFrame(() => {//箭头函数的写法
speed.value = 100;//其实显示的就是进度条的进度,结束了就是100%
dom.style.width = speed.value + '%'
})
}, 500)
}
defineExpose({//defineExpose 可以将方法主动暴露出来,通过对象的形式。然后能够在父组件中进行接收
//当父组件通过模板引用的方式获取到当前组件的实例,获取到的实例会像这样 { startLoading: number, endLoading: number } (ref 会和在普通实例中一样被自动解包)
startLoading,
endLoading
})
</script>
<style scoped lang="less">//样式
.wraps {
position: fixed;
top: 0;
width: 100%;//这些都是决定进度条的样式的
height: 2px;
.bar {
height: inherit;
width: 0;
background: blue;
}
}
</style>
main.ts
import loadingBar from './components/loadingBar.vue'
const Vnode = createVNode(loadingBar)//createVNode是Vue3中提供的方法,用于创造DOM节点
render(Vnode, document.body)
console.log(Vnode);
router.beforeEach((to, from, next) => {
Vnode.component?.exposed?.startLoading()//问号为可选的意思
})
router.afterEach((to, from) => {
Vnode.component?.exposed?.endLoading()
})
上述牵扯到的知识点补充:
计时器一直是javascriptz动画的核心技术。而编写动画循环的关键是要知道延迟时间多长合适。一方面,循环间隔必须足够短,这样
才能让不同的动画效果显得平滑流畅;另一方面,循环间隔还要足够长,这样才能确保浏览器有能力渲染产生的变化大多数电脑显示器的刷新频率是60Hz,大概相当于每秒钟重绘60次。大多数浏览器都会对重绘操作加以限制,不超过显示器的重绘频率,因为即使超过那个频率用户体验也不会有提升。因此,最平滑动画的最佳循环间隔是1000ms/60,约等于16.6ms
而setTimeout和setIntervall的问题是,它们都不精确。它们的内在运行机制决定了时间间隔参数实际上只是指定了把动画代码添加到浏览器U线程队列中以等待执行的时间。如果队列前面已经加入了其他任务,那动画代码就要等前面的任务完成后再执行
requestAnimationFrame.采用系统时间间隔,保持最佳绘制效率,不会因为间隔时间过短,造成过度绘制,增加开销;也不会因为间隔时间太长,使用动画卡顿不流畅,让各种网页动画效果能够有一个统一的刷新机制,从而节省系统资源,提高系统性能,改善视觉效果
requestAnimationFrame 比起 setTimeout、setInterval 的优势主要有两点:
1、requestAnimationFrame 会把每一帧中的所有 DOM 操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率,一般来说,这个频率为每秒 60 帧。
2、在隐藏或不可见的元素中,requestAnimationFrame 将不会进行重绘或回流,这当然就意味着更少的的 cpu,gpu 和内存使用量。