图片懒加载:原生js实现和Vue实现

135 阅读2分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路。

HTTP请求:

1.请求带有n张图片的html文件,会发送n+1次请求,因为在浏览器解析html时,遇见src就会请求src后面的内容。

2.图片加载是同步的,当图片量过多时,加载图片时会造成浏览器阻塞。

图片懒加载的意思是按需加载,当图片出现在可视区时再加载。

1.原生js实现

这里采用原生js实现图片懒加载,计算出图片是否出现在可视区域,当图片出现的可视区域时,再加载图片。

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>原生JS实现图片懒加载</title>
    <style>
        img.item {
            display: inline-block;
            width: 8%;
        }
    </style>
</head>

<body>
    <!-- alt 属性是一个必需的属性,它规定在图像无法显示时的替代文本。 
        data-* 全局属性:构成一类名称为自定义数据属性的属性,可以通过HTMLElement.dataset来访问。 -->
    <div class="img-item">
        <img class="item" alt="loading" data-src="./img/GEM1.jpeg">
    </div>
    <div class="img-item">
        <img class="item" alt="loading" data-src="./img/GEM2.jpeg">
    </div>
    <div class="img-item">
        <img class="item" alt="loading" data-src="./img/GEM3.jpeg">
    </div>
    <div class="img-item">
        <img class="item" alt="loading" data-src="./img/GEM4.jpeg">
    </div>
    <div class="img-item">
        <img class="item" alt="loading" data-src="./img/GEM5.jpeg">
    </div>
    <div class="img-item">
        <img class="item" alt="loading" data-src="./img/GEM6.jpeg">
    </div>
    <div class="img-item">
        <img class="item" alt="loading" data-src="./img/GEM7.jpeg">
    </div>
    <div class="img-item">
        <img class="item" alt="loading" data-src="./img/GEM8.jpeg">
    </div>
</body>

<script>
    /*
    计算图片是否在可视区
    1.获取屏幕可视窗口高度 document.documentElement.clientHeight
    2.获取元素相对于文档顶部的距离 element.offsetTop
    3.获取浏览器窗口顶部与文档顶部之间的距离,也就是滚动条滚动的距离 document.documentElement.scrollTop
    元素在可视区域内的条件 2-3 < 1
    */
    function isView(element) {
        return element.offsetTop - document.documentElement.scrollTop < document.documentElement.clientHeight;
        console.log(element.offsetTop - document.documentElement.scrollTop < document.documentElement.clientHeight);
    }

    /*
    遍历图片
    */
    function eachImgs() {
        // 获取元素
        var img = Array.from(document.querySelectorAll('.item'));
        // 遍历元素
        img.forEach(function (value, index) {
            // 判断元素是否在可视范围内
            if (isView(value)) {
                // 若在可是范围内,则加上src
                dataSrc(value);
            }
        })
    }

    /*
    给元素加上src属性,
    */
    function dataSrc(element) {
        if (!element.src) {
            element.src = element.dataset.src;
        }
    }

    eachImgs();
    /**
      防抖+监听滚动条滚动事件
    */
    var scrollTime = null;
    window.addEventListener('scroll', function () {
        if (scrollTime) {
            clearInterval(scrollTime);
        }
        scrollTime = setTimeout(() => {
            eachImgs();
            console.log('滚动条滚动事件');
        }, 100)
    })

    var wheelTime = null;
    window.addEventListener('mousewheel',function(){
        if (wheelTime) {
            clearInterval(wheelTime);
        }
        wheelTime = setTimeout(() => {
            eachImgs();
            console.log('鼠标滚轮事件');
        }, 100)
    })
</script>

</html>

image.png

开始加载页面时,只有图片1和2在可视图区域。滑动滚轮或下拉滚动条。 其他图片就慢慢加载出来了。

image.png

这只是简单的实现,还有可优化的地方。

2.Vue实现

安装插件简单实现

使用v-bind而不用懒加载时,图片会同步加载出来。

<template>
  <div>
    <h1>安装插件实现vue懒加载</h1>
    <div v-for="(item,index) in list" :key="index">
      <img style="width:8%" :src="item" alt="loading"/>
    </div>
  </div>
</template>

<script>
export default {
  name: 'NoLazyLoad',
  // 图片列表
  data(){
    return{
      list: [
        require('../assets/img/GEM1.jpeg'),
        require('../assets/img/GEM2.jpeg'),
        require('../assets/img/GEM3.jpeg'),
        require('../assets/img/GEM4.jpeg'),
        require('../assets/img/GEM5.jpeg'),
        require('../assets/img/GEM6.jpeg'),
        require('../assets/img/GEM7.jpeg'),
        require('../assets/img/GEM8.jpeg'),
      ]
    }
  }
}
</script>

<style lang="less" scoped>
  
</style>

image.png

使用图片懒加载插件,安装插件:

npm install vue-lazyload --save-dev

先在main.js中引入和使用安装的插件,再将上面的:src="item"换成v-lazy="item"即可。

main.js

import Vue from 'vue'
import App from './App.vue'
import VueLazyLoad from 'vue-lazyload'

Vue.config.productionTip = false
Vue.use(VueLazyLoad)

new Vue({
  render: h => h(App),
}).$mount('#app')

在引入时,也添加自定义配置。

main.js

import Vue from 'vue'
import App from './App.vue'
import VueLazyLoad from 'vue-lazyload'

Vue.config.productionTip = false
// Vue.use(VueLazyLoad)

Vue.use(VueLazyLoad, {
  preLoad: 1.3,
  error: require('./assets/img/logo.png'),
  loading: require('./assets/img/logo.png'),
  attempt: 1
  })

new Vue({
  render: h => h(App),
}).$mount('#app')

相应vue文件

<template>
  <div>
    <h1>安装插件实现vue懒加载</h1>
    <div v-for="(item,index) in list" :key="index">
      <img style="width:8%" v-lazy="item" alt="loading"/>
    </div>
  </div>
</template>

<script>
export default {
  name: 'lazyLoad',
  // 图片列表
  data(){
    return{
      list: [
        require('../assets/img/GEM1.jpeg'),
        require('../assets/img/GEM2.jpeg'),
        require('../assets/img/GEM3.jpeg'),
        require('../assets/img/GEM4.jpeg'),
        require('../assets/img/GEM5.jpeg'),
        require('../assets/img/GEM6.jpeg'),
        require('../assets/img/GEM7.jpeg'),
        require('../assets/img/GEM8.jpeg'),
      ]
    }
  }
}
</script>

<style lang="less" scoped>
  
</style>

image.png

在一开始加载页面时,只有图片1在可可视区域,所以只加载了图片1。滑动滚轮或下拉滚动条。

其他图片就慢慢加载出来了。

image.png

懒加载的优点就是能防止页面一次性向服务器响应大量请求导致服务器响应慢,防止页面卡顿或崩溃等问题。