# 作用与定义
为给客户更好的客户体验,首屏组件加载速度更快一些,解决白屏问题。
懒加载简单来说就是延迟加载或按需加载,即在需要的时候的时候进行加载。
# 路由懒加载
# 未使用懒加载的路由代码如下
| import {createRouter, createWebHashHistory} from 'vue-router' |
| import HomeView from '../views/HomeView.vue' |
| import About from '../views/About.vue' |
| |
| |
| const routes = [ |
| |
| { |
| path: '/', component: HomeView, |
| }, |
| { |
| path: '/About', component: About, |
| }, |
| |
| ] |
| export default router |
# 使用路由懒加载的三种方式
- 复杂但可显示组件名的方式
| import { createRouter, createWebHashHistory } from 'vue-router' |
| import HomeView from '../views/HomeView.vue' |
| |
| const routes = [ |
| { |
| path: '/', |
| name: 'home', |
| component: HomeView |
| }, |
| { |
| path: '/about', |
| name: 'about', |
| <!-- --> |
| component: () => import('../views/AboutView.vue') |
| } |
| ] |
| |
| const router = createRouter({ |
| history: createWebHashHistory(), |
| routes |
| }) |
| |
| export default router |
- 简单但不显示组件名的方式
| import { createRouter, createWebHashHistory } from 'vue-router' |
| const HomeView = () => import('../views/HomeView.vue') |
| const About = () => import('../views/AboutView.vue') |
| |
| const routes = [ |
| { |
| path: '/', |
| name: 'home', |
| component: HomeView |
| }, |
| { |
| path: '/about', |
| name: 'about', |
| component: About |
| } |
| ] |
| |
| const router = createRouter({ |
| history: createWebHashHistory(), |
| routes |
| }) |
| |
| export default router |
- 琢磨了一下,经过测试,既方便又可以显示组件名的方法 以后懒加载可以使用这个方法
| import { createRouter, createWebHashHistory } from 'vue-router' |
| const HomeView = () => import('../views/HomeView.vue') |
| const AboutView = () => import('../views/AboutView.vue') |
| |
| const routes = [ |
| { |
| path: '/', |
| name: 'home', |
| component: HomeView |
| }, |
| { |
| path: '/about', |
| name: 'about', |
| component: AboutView |
| } |
| ] |
| |
| const router = createRouter({ |
| history: createWebHashHistory(), |
| routes |
| }) |
| |
| export default router |
# 组件数据懒加载
我们可以使用 @vueuse/core
中的 useIntersectionObserver
来实现监听进入可视区域行为,但是必须配合 vue3.0 的组合 API 的方式才能实现。
# 安装
npm i @vueuse/core
# 分析 useIntersectionObserver
函数
| |
| import { useIntersectionObserver } from '@vueuse/core' |
| |
| |
| const { stop } = useIntersectionObserver( |
| |
| target, |
| |
| |
| ([{ isIntersecting }], observerElement) => { |
| |
| } |
| ) |
# 封装代码 逻辑复用
| |
| import {useIntersectionObserver} from "@vueuse/core/index"; |
| import {ref} from "vue"; |
| |
| |
| * 数据懒加载函数 |
| * @param apiFn - API 函数 |
| */ |
| export const useLazyData = ( apiFn) => { |
| const target = ref(null) |
| const result = ref([]) |
| |
| const {stop} = useIntersectionObserver( |
| |
| target, |
| ([{isIntersecting}], observerElement) => { |
| |
| if (isIntersecting) { |
| console.log('进入可视区') |
| stop() |
| |
| apiFn().then((data) => { |
| result.value = data.result |
| }) |
| } |
| }, |
| |
| { |
| threshold: 0 |
| } |
| ) |
| return {target,result} |
| } |
# 在页面中使用
| + <HomePanel ref="target" title="新鲜好物" subTitle="新鲜出炉 品质靠谱"> |
| |
| import { findNew } from '@/api/home' |
| +++ import { useLazyData } from '@/hooks' |
| export default { |
| name: 'HomeNew', |
| components: { HomePanel, HomeSkeleton }, |
| setup () { |
| +++ const { target, result } = useLazyData(findNew) |
| +++ return { target, list:result } |
| } |
| } |
| </script> |
# 踩坑
基础没打好,封装好数据懒加载代码后,没有实现效果找了亿点时间问题后发现在这个地方
| |
| const { target, result } = useLazyData(findNew) |
如果是需要传参的函数可以放一个回调函数进去,实在是太妙了!
| const { target, result } = useLazyData( () => findBrand(10) ) |
# 图片懒加载
# 方法 1(原生 WebAPI 写法)
src/components/library/index.js
此路径专门用于 扩展 vue 原有的功能:全局组件,自定义指令,挂载原型方法。
| |
| import defaultImg from "@/assets/images/200.png" |
| |
| |
| |
| |
| |
| |
| |
| export default { |
| |
| install(app) { |
| |
| |
| |
| |
| defineDirective(app) |
| } |
| } |
| |
| |
| const defineDirective = (app) => { |
| |
| |
| app.directive('lazy', { |
| |
| mounted(el, binding) { |
| |
| const observe = new IntersectionObserver(([{isIntersecting}]) => { |
| if (isIntersecting) { |
| |
| observe.unobserve(el) |
| |
| |
| el.onerror = () => { |
| |
| el.src = defaultImg |
| } |
| el.src = binding.value |
| } |
| }, { |
| threshold: 0 |
| }) |
| observe.observe(el) |
| } |
| }) |
| } |
在 main.js
中导入
| |
| import XtxUI from '@/components/library' |
| |
| |
| createApp(App).use(XtxUI).mount('#app') |
使用方法
| <div> |
| <img alt="" v-lazy="list.picture" /> |
| </div> |
# 方法二(npm 包)
- 安装
npm i vue3-lazy -S
main.js
中全局注册
| import {createApp} from 'vue' |
| import App from './App.vue' |
| import router from './router' |
| import store from './store' |
| ++import defaultImg from '@/assets/images/200.png' |
| |
| |
| import lazyPlugin from 'vue3-lazy' |
| |
| createApp(App) |
| .use(store) |
| .use(router) |
| ++ .use(lazyPlugin,{ |
| loading: defaultImg, |
| error: defaultImg |
| }).mount('#app') |
- 使用
| <div> |
| <img alt="" v-lazy="list.picture" /> |
| </div> |
4. 上一个方法可以看见加载失败的图片,这个方法不可以,在没有找到更好的方法之前,还是先用上一个方法吧。