一开始只加载前面部分,随着下滑,进入视口区域才加载后面的内容。
自定义一个到达视口区域后自动加载的指令img-lazy
,然后在<img/>
中使用v-img-lazy
属性实现图片的懒加载
官方文档
main.js
// 定义全局自定义指令
app.directive("img-lazy",{
mounted(el,binding){
// el: 指令绑定的那个元素 img
// binding: binging.value 绑定到表达式的值=>这里是图片url
console.log(el,binding.value);
}
})
使用vueUse
中提供功能。useIntersectionObserver
函数能够判断。
// 定义全局自定义指令
app.directive("img-lazy", {
mounted(el, binding) {
// el: 指令绑定的那个元素 img
// binding: binging.value 绑定到表达式的值=>这里是图片url
// console.log(el,binding.value);
// stop用于停止继续监听
const {stop} = useIntersectionObserver(
el,
([{ isIntersecting }]) => {
// isIntersecting :bool, 是否进入视口区域
if(isIntersecting){
// 将Url赋值给src后就会自动的去请求该url, 注意需要将原来的src删除
el.src = binding.value
}
},
)
}
})
上面是在main.js
入口函数中实现的懒加载,我们应该将实现其移动到单独的地方,然后只在这里注册。
可以使用插件的形式实现。插件的实现和扩展方法有些类似,在插件的定义中可以使用install()
获取到使用该插件的app
对象,还可以传递参数。
将插件写在directives
文件夹中,其基本语法是:
const lazyImgPlugin = {
install(app, options) {
// 配置此应用
}
}
我们将之前写在main.js
中的内容剪切到这里面,然后导入判断是否进入视口的函数即可。写完之后将该插件导出,然后在main.js
中导入该插件,使用app.use()
注册该插件。
useIntersectionObserver
默认是一直监听是否进入视口的,即加载图片之后还是会在反复进入视口时反复执行对应的回调。
可以从useIntersectionObserver
中解构出stop
函数,该函数用于结束监听,在第一次加载图片之后就是要该函数结束掉监听。
const {stop} = useIntersectionObserver(
el,
([{ isIntersecting }]) => {
// isIntersecting :bool, 是否进入视口区域
if (isIntersecting) {
// 将Url赋值给src后就会自动的去请求该url, 注意需要将原来的src删除
el.src = binding.value
stop()
}
},
)
路由传参可以使用restfull的params,也可以是查询字符串的query。传递之后使用vue-router
中的useRoute
来获取当前路由的参数。
const route = useRoute()
const id = route.params.id
需要显示当前那个路由是被激活的,方便用户知道当前是在哪个页面。Router-Link
组件支持该功能,其active-class
对应css样式,表示该路由处于被激活状态时的样式。
路由导航存在缓存,只在路由参数变化时其并不会重新导航加载组件,而是进行组件复用,这就意味着生命周期函数也不会被调用。 解决方法:
- 让组件实例不服用,每次强制销毁,在
RouterView
组件绑定独一无二的key,<RouterView :key="$route.fullPath"/>
。缺点是当前路由下的所有资源都会刷新,做不到只刷新部分. - 使用监听(精细化控制),有专门监听路由变化的
beforeRouteUpdate
导航钩子; 或者是watchEffect(route,()=>{})
,监听响应式数据的变化并调用回调函数。项目里面使用的是beforeRouteUpdate
业务逻辑变多了以后如果放在一个文件里面就很乱,所以将每一个业务逻辑单独封装,使用是单独调用即可,增强了可读性。直接搬代码即可,学习到的点是:使用的hooks
(各种AOP钩子)其实类似于注册该钩子,注册之后就会在其生命周期发生时出发,相当于注册到vue的整个对象中去了。
el-form
分为三个部分。el-form
、el-item
、el-input
。
- 响应式表单对象和rules对象分别绑定到
el-form
的:model
和:rules
上。 - 在
el-item
的prop
上绑定校验规则中的校验名。 - 将数据使用
v-model
进行双向绑定到el-input
。
自定义校验规则将required
、min
之类的规则改为validator
并传入一个函数,必须有这三个参数,且不论是否通过校验都需要执行callback
validator: (rule, value, callback) => {
if (value == false) {
callback(new Error('请同意协议'))
} else {
callback()
}
}
使用vue-router
中的useRouter
方法回去到router
实例,有push
和replace
两种路由跳转方式,push
是将当前的路由信息记录到浏览器的历史记录栈中,此时用户可以使用浏览器的后退功能回到跳转前的位置;replace
是将当前的路由信息直接替换为要跳转的路由地址,不会像浏览器历史记录栈中添加新的路由信息,这种方法一般用于不希望用户跳转回来的情况,如登录成功后的跳转。这两种方法都是不会刷新页面请求的。
将所有涉及到需要存储数据的操作都封装到pinia的action中,使用的组件只需要调用其action后,再使用数据state即可。
将登录接口的调用放在pinia中,用其action获取数据后放入state,将state和action导出后和全局使用。
将用户的Token持久化到localStorage
axios的请求都是异步请求,会返回一个Promise
对象,所以我们一般使用async
和await
进行异步编程。在拦截器使用时会将响应拦截下来做预处理,如果这个响应是成功了,则是fulfilled
状态,会继续回到原来的执行流程继续执行.then()
中的内容;而如果响应是失败,则是reject
状态,会进入到.catch()
中的内容。而我们如果使用await
来等待请求,则会在fulfilled
时继续原来的流程执行,而在reject
是将错误信息向上一步一步抛出直到有catch
来捕获后进行处理,不会继续原流程执行。在vue3中有个onErrorCaptured
钩子可以全局捕获组件的错误。如果不显式进行捕获处理,系统也不会崩溃,应该是vue3中有相应处理,比如将信息请求错误信息打印到控制台。
大多数现代的浏览器会在未捕获的 Promise 拒绝(uncaught promise rejection)时自动将错误信息打印到控制台。这个与vue3框架处理的信息不一样。