Vue懒加载 - web前端 | MrNobody = MrNobody's Blog = 保持呼吸 不要断气

# 作用与定义

为给客户更好的客户体验,首屏组件加载速度更快一些,解决白屏问题。
懒加载简单来说就是延迟加载或按需加载,即在需要的时候的时候进行加载。

# 路由懒加载

# 未使用懒加载的路由代码如下

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

# 使用路由懒加载的三种方式

  1. 复杂但可显示组件名的方式
import { createRouter, createWebHashHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
const routes = [
  {
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    path: '/about',
    name: 'about',
    <!-- /*webpackChunkName: 组件名称 */ -->
    component: () => import(/* webpackChunkName: "about" */'../views/AboutView.vue')
  }
]
const router = createRouter({
  history: createWebHashHistory(),
  routes
})
export default router
  1. 简单但不显示组件名的方式
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
  1. 琢磨了一下,经过测试,既方便又可以显示组件名的方法 以后懒加载可以使用这个方法
import { createRouter, createWebHashHistory } from 'vue-router'
const HomeView = () => import(/*webpackChunkName:"Home"*/'../views/HomeView.vue')
const AboutView = () => import(/*webpackChunkName: "About"*/'../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 函数

//  导入 useIntersectionObserver  函数
import { useIntersectionObserver } from '@vueuse/core'
// 1. stop 是停止观察是否进入或移出可视区域的行为    
const { stop } = useIntersectionObserver(
// 2. target 是观察的目标 dom 容器,必须是 dom 容器,而且是 vue3.0 方式绑定的 dom 对象
  target,
// 3.  isIntersecting 是否进入可视区域,true 是进入 false 是移出
// 4. observerElement 被观察的 dom
  ([{ isIntersecting }], observerElement) => {
  // 在此处可根据 isIntersecting 来判断,然后做业务
  }
)

# 封装代码 逻辑复用

// 提供复用逻辑的函数 (钩子)
import {useIntersectionObserver} from "@vueuse/core/index";
import {ref} from "vue";
/**
 * 数据懒加载函数
 * @param apiFn - API 函数
 */
export const useLazyData = ( apiFn) => {
    const target = ref(null) // 监听的目标元素
    const result = ref([])   // 返回的数据
    //stop 停止观察
    const {stop} = useIntersectionObserver(
        // 监听的目标元素
        target,
        ([{isIntersecting}], observerElement) => {
            //isIntersecting 是否进入可视区
            if (isIntersecting) {
                console.log('进入可视区')
                stop()
                // 调用 API 函数获取数据
                apiFn().then((data) => {
                    result.value = data.result
                })
            }
        },
        // 配置选项,相交的比例大于 0 就触发
        {
            threshold: 0
        }
    )
    return {target,result}
}

# 在页面中使用

+   <HomePanel ref="target" title="新鲜好物" subTitle="新鲜出炉 品质靠谱">
  <!-- 看见哪个盒子加载数据 就给哪个盒子加 ref="target" -->
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"
// Vue2 全局注册组件
// Vue.component (' 组件名 ', 组件)
// Vue3 全局注册组件
//app.component (' 组件名 ', 组件)
export default {
    //install 这种写法以后是提供给 app.use () 安装组件库用的
    install(app) {
        // Vue3 全局注册组件
        // app.component(XtxSkeleton.name, XtxSkeleton)
        // 定义指令
        defineDirective(app)
    }
}
// 定义指令
const defineDirective = (app) => {
    // 图片懒加载指令
    // 原理:先存储图片地址 不能在 src 上 当图片进入可视区 将你存储图片的地址设置给图片元素即可
    app.directive('lazy', {
        // 配置选项
        mounted(el, binding) {
            // 创建一个观察对象,来观察当前使用指令的元素
            const observe = new IntersectionObserver(([{isIntersecting}]) => {
                if (isIntersecting) {
                    // 停止观察
                    observe.unobserve(el)
                    // 把指令的值设置给 el 的 src 属性,binding.value 就是指令的值
                    // 处理图片加载失败
                    el.onerror = () => {
                        //  加载失败,设置默认图
                        el.src = defaultImg
                    }
                    el.src = binding.value
                }
            }, {
                threshold: 0
            })
            observe.observe(el)
        }
    })
}

main.js 中导入

// 导入自己的 ui 组件库
import XtxUI from '@/components/library'
createApp(App).use(XtxUI).mount('#app')

使用方法

<div>
   <img alt="" v-lazy="list.picture" />
</div>

# 方法二(npm 包)

  1. 安装

npm i vue3-lazy -S

  1. 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')
  1. 使用
<div>
 <img alt="" v-lazy="list.picture" />
</div>

4. 上一个方法可以看见加载失败的图片,这个方法不可以,在没有找到更好的方法之前,还是先用上一个方法吧。

更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

Mr_Nobody 微信支付

微信支付

Mr_Nobody 支付宝

支付宝

Mr_Nobody 贝宝

贝宝