面试官刁难系列一:手写图片懒加载代码 Bertha 。 2022-09-08 11:51 167阅读 0赞 ## 前言 ## 今天是跟面试官开撕的第一天,当你过五关斩六将终于来到面试官面前时,他可能在面试你之前写过如下的代码: <el-image :src="url" lazy></el-image> 没错,就是这么轻描淡写的一句代码,他心里却有了不一样的想法。lazy 这个属性它是如何实现图片懒加载的?请说说你的思路。 ![cb689ea511371ee9712c5ecc7e3b14ca.gif][] 头脑顿时一场空。"只怪我平时只*复制粘贴*写业务代码了,草率了!"你可能此时是这样想的。幸运的是,今天是开撕的一天,今天就甩出你自信的代码给面试官。 ### element-plus实现思路 ### 翻看Element-plus源码得知在`packages/comonents/image`下的src找到index.vue页面,*lazy*属性是通过子父组件形式的*props*方式传递进来的: ![cbb3a6a48ceeba49aec622800f731874.png][] 然后在 *onMounted* 函数里判断是否使用了*lazy*,使用的话执行*addLazyLoadListener*事件,否则直接加载图片出来。 onMounted(() => { if (props.lazy) { nextTick(addLazyLoadListener) } else { //后面会讲到 loadImage() } }) 接着就来到了这里: ![e9a83065400108ed08295281d484eea8.png][] `const { scrollContainer } = props` 这句代码就将父组件传入的*props*拿到。接着就是获取滚动元素的DOM了。来到第235行代码: _lazyLoadHandler = throttle(handleLazyLoad, 200) 我们看到这里使用了*throttle*节流函数,引入的是*throttle-debounce*库,传入的200作为间歇时间。库文件地址:(https://www.npmjs.com/package/throttle-debounce) import throttle from 'lodash/throttle' 接着使用*setTimeout*函数在100浩渺后执行*handleLazyLoad*方法。 function handleLazyLoad() { if (isInContainer(container.value, _scrollContainer)) { loadImage() removeLazyLoadListener() } } 这里注意*isInContainer*这个方法,它是从\*@element-plus/utils/dom\*导入的。我痛过引入路径找到这个方法。 export const isInContainer = ( el: HTMLElement, container: HTMLElement, ): boolean => { if (isServer || !el || !container) return false const elRect = el.getBoundingClientRect() let containerRect: Partial<DOMRect> if ( [window, document, document.documentElement, null, undefined].includes( container, ) ) { containerRect = { top: 0, right: window.innerWidth, bottom: window.innerHeight, left: 0, } } else { containerRect = container.getBoundingClientRect() } return ( elRect.top < containerRect.bottom && elRect.bottom > containerRect.top && elRect.right > containerRect.left && elRect.left < containerRect.right ) } 可以看到使用isInContainer方法时传入的*container.value, \_scrollContainer*使用*getBoundingClientRect*这个API来比较当前Image组件是否在当前滚动区域的可视区。这个API可以获取: * elRect.top:元素上边到视窗上边的距离 * elRect.right:元素右边到视窗左边的距离 * elRect.bottom:元素下边到视窗上边的距离 * elRect.left:元素左边到视窗左边的距离 当判断当前Image组件在滚动可视区时才执行*loadImage*方法。 const loadImage = () => { if (isServer) return const attributes = attrs.value // reset status loading.value = true hasLoadError.value = false //创建一个img实例 const img = new Image() //onload 事件在图片加载完成后立即执行 img.onload = (e) => handleLoad(e, img) img.onerror = handleError // bind html attrs // so it can behave consistently //这句代码是将设置在属性全部设置在img标签上 Object.keys(attributes).forEach((key) => { // avoid onload to be overwritten if (key.toLowerCase() === 'onload') return const value = attributes[key] img.setAttribute(key, value) }) img.src = props.src } 这样就完成了懒加载的大概过程。 ### 自行手写图片懒加载实现思路 ### 我们写一个简易的图片懒加载版本。当不使用懒加载直接给src设置图片路径时,倘若图片太大或者资源还没加载完成,img标签就会出现空白情况,为此我们需要利用上面提到的*onload*事件,等图片资源加载完成我再设置src属性为图片的地址那就不会出现空白情况啦。 手写代码之前,我们需要知道的是:什么是自执行函数? ![55f6b873144ebae5156a46d8eab76761.gif][] 我们先来看看普通的函数。 //定义一个函数 let total =0 function sum (a,b) { return total = a + b } *Q:那么我们想执行这个函数需要怎么做呢? A:如果想执行它,就必须得调用它,并且还得给它传参。* const hh = sum(1,2) console.log(hh) // =>3 那*自执行函数*呢?自执行函数就是当它被定义出来,就会自动执行的函数。不需要调用,传参也很方便。就上面的函数,用自执行函数定义就是这样: let total = 0 (function sum (a,b) { return total = a + b })(1,2) console.log(total) // => 3 ![cace624fe7eb2f07c124320764b8fc07.gif][] 所以,这就很有用处了。 const myImage = (function(){ // 创建一个img标签 let imgNode = document.createElement('img') // 将创建好的img标签添加到body上 document.body.appendChild(imgNode) // new一个Image实例 let img = new Image() // 图片资源加载完成后将地址设置给上面创建好的img标签的src属性 img.onload = function() { imgNode.src = img.src } return { setSrc(src){ // 首先将加载中的图片设定给img的src属性 imgNode.src = '图片加载中的图片(可本地地址)' // 将传入的地址缓存到上面创建的实例的src中 img.src = src } } })()// 自执行函数 // 使用 myImage.setSrc('https://www.baidu.com/img/bd_logo1.png?where=super') 调戏面试官的一天就这么轻松愉快地结束了。当你面试后真的遇到了别忘记回来点个赞哦。 ##### 文章来源于公众号《前端发现》 ##### [cb689ea511371ee9712c5ecc7e3b14ca.gif]: /images/20220829/4b8570ae5b5b4e09844e8b37ecc1b4ef.png [cbb3a6a48ceeba49aec622800f731874.png]: /images/20220829/f18e8d7634a9498c80390ef525aed82f.png [e9a83065400108ed08295281d484eea8.png]: /images/20220829/5d5640adeaf74fb0acb771045b9cb7a5.png [55f6b873144ebae5156a46d8eab76761.gif]: /images/20220829/c6d5ef31a16347f6a1aa35a1e6316a85.png [cace624fe7eb2f07c124320764b8fc07.gif]: /images/20220829/2949bb6f61fe45c98ed3efb1f9dd53e3.png
相关 图片懒加载 function lazyLoadImg() { var img = document.getElementsByTagName('img'); s 谁践踏了优雅/ 2022年09月28日 13:05/ 0 赞/ 282 阅读
相关 面试官刁难系列一:手写图片懒加载代码 前言 今天是跟面试官开撕的第一天,当你过五关斩六将终于来到面试官面前时,他可能在面试你之前写过如下的代码: <el-image :src="url" lazy> Bertha 。/ 2022年09月08日 11:51/ 0 赞/ 168 阅读
相关 图片懒加载 1.引入js jquery.lazyload.js(如下) / Lazy Load - jQuery plugin for lazy loading 缺乏、安全感/ 2022年06月16日 06:44/ 0 赞/ 367 阅读
相关 图片懒加载 懒加载的意义[(在线demo预览)][demo] 尽管很多公司的网页都有一些限制,比如页面的最大的图片大小不得大于50k,也有很多图片优化工具fis3、gulp等等,但是 痛定思痛。/ 2022年06月04日 07:58/ 0 赞/ 407 阅读
相关 图片懒加载 本文主要通过以下几方面来说明懒加载技术的原理,个人前端小菜,有错误请多多指出 一、什么是图片滚动加载? 通俗的讲就是:当访问一个页面的时候,先把img元素或是其他元素的 你的名字/ 2022年05月28日 05:29/ 0 赞/ 396 阅读
相关 图片懒加载 在实际的项目开发中,我们通常会遇见这样的场景:一个页面有很多图片,而首屏出现的图片大概就一两张,那么我们还要一次性把所有图片都加载出来吗?显然这是愚蠢的,不仅影响页面渲染速度, 偏执的太偏执、/ 2022年05月28日 02:07/ 0 赞/ 438 阅读
相关 图片懒加载 <!--<!doctype html>--> <!--<html lang="en">--> <!--<head>--> <!--<me 亦凉/ 2022年05月23日 12:19/ 0 赞/ 381 阅读
相关 图片懒加载 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> r囧r小猫/ 2022年05月21日 06:54/ 0 赞/ 411 阅读
相关 图片懒加载 \[外链图片转存失败(img-vbwUXXxJ-1563574134995)([https://upload-images.jianshu.io/upload\_images/ 川长思鸟来/ 2021年09月30日 00:24/ 0 赞/ 710 阅读
还没有评论,来说两句吧...