# 作用与定义
为给客户更好的客户体验,首屏组件加载速度更快一些,解决白屏问题。
懒加载简单来说就是延迟加载或按需加载,即在需要的时候的时候进行加载。
# 路由懒加载
# 未使用懒加载的路由代码如下
|  | 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. 上一个方法可以看见加载失败的图片,这个方法不可以,在没有找到更好的方法之前,还是先用上一个方法吧。