<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          面試官刁難系列一:手寫圖片懶加載代碼

          共 6380字,需瀏覽 13分鐘

           ·

          2021-09-02 14:25

          ????關(guān)注后回復(fù) “進群” ,拉你進程序員交流群????

          作者丨前端發(fā)現(xiàn)者

          來源丨前端發(fā)現(xiàn)

          前言

          今天是跟面試官開撕的第一天,當你過五關(guān)斬六將終于來到面試官面前時,他可能在面試你之前寫過如下的代碼:

          <el-image :src="url" lazy></el-image>

          沒錯,就是這么輕描淡寫的一句代碼,他心里卻有了不一樣的想法。lazy 這個屬性它是如何實現(xiàn)圖片懶加載的?請說說你的思路。

          頭腦頓時一場空。"只怪我平時只復(fù)制粘貼寫業(yè)務(wù)代碼了,草率了!"你可能此時是這樣想的。幸運的是,今天是開撕的一天,今天就甩出你自信的代碼給面試官。

          element-plus實現(xiàn)思路

          翻看Element-plus源碼得知在packages/comonents/image下的src找到index.vue頁面,lazy屬性是通過子父組件形式的props方式傳遞進來的:

          然后在 onMounted 函數(shù)里判斷是否使用了lazy,使用的話執(zhí)行addLazyLoadListener事件,否則直接加載圖片出來。

          onMounted(() => {
            if (props.lazy) {
              nextTick(addLazyLoadListener)
            } else {
              //后面會講到
              loadImage()
            }
          })

          接著就來到了這里:

          const { scrollContainer } = props 這句代碼就將父組件傳入的props拿到。接著就是獲取滾動元素的DOM了。來到第235行代碼:

          _lazyLoadHandler = throttle(handleLazyLoad, 200)

          我們看到這里使用了throttle節(jié)流函數(shù),引入的是throttle-debounce庫,傳入的200作為間歇時間。庫文件地址:(https://www.npmjs.com/package/throttle-debounce)

          import throttle from 'lodash/throttle'

          接著使用setTimeout函數(shù)在100毫秒后執(zhí)行handleLazyLoad方法。

          function handleLazyLoad() {
            if (isInContainer(container.value, _scrollContainer)) {
              loadImage()
              removeLazyLoadListener()
            }
          }

          這里注意isInContainer這個方法,它是從*@element-plus/utils/dom*導(dǎo)入的。痛過引入路徑找到這個方法。

          export const isInContainer = (
            el: HTMLElement,
            container: HTMLElement,
          ): boolean => {
            if (isServer || !el || !container) return false

            const elRect = el.getBoundingClientRect()
            let containerRect: Partial<DOMRect>

            if (
              [windowdocumentdocument.documentElement, nullundefined].includes(
                container,
              )
            ) {
              containerRect = {
                top0,
                rightwindow.innerWidth,
                bottomwindow.innerHeight,
                left0,
              }
            } 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組件是否在當前滾動區(qū)域的可視區(qū)。這個API可以獲取:

          • elRect.top:元素上邊到視窗上邊的距離
          • elRect.right:元素右邊到視窗左邊的距離
          • elRect.bottom:元素下邊到視窗上邊的距離
          • elRect.left:元素左邊到視窗左邊的距離

          當判斷當前Image組件在滾動可視區(qū)時才執(zhí)行loadImage方法。

          const loadImage = () => {
            if (isServer) return

            const attributes = attrs.value

            // reset status
            loading.value = true
            hasLoadError.value = false
            //創(chuàng)建一個img實例
            const img = new Image()
            //onload 事件在圖片加載完成后立即執(zhí)行
            img.onload = (e) => handleLoad(e, img)
            img.onerror = handleError

            // bind html attrs
            // so it can behave consistently
            //這句代碼是將設(shè)置在屬性全部設(shè)置在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
          }

          這樣就完成了懶加載的大概過程。

          自行手寫圖片懶加載實現(xiàn)思路

          我們寫一個簡易的圖片懶加載版本。當不使用懶加載直接給src設(shè)置圖片路徑時,倘若圖片太大或者資源還沒加載完成,img標簽就會出現(xiàn)空白情況,為此我們需要利用上面提到的onload事件,等圖片資源加載完成我再設(shè)置src屬性為圖片的地址那就不會出現(xiàn)空白情況啦。

          手寫代碼之前,我們需要知道的是:什么是自執(zhí)行函數(shù)?

          我們先來看看普通的函數(shù)。

          //定義一個函數(shù)
          let total  =0
          function sum (a,b{
            return total = a + b
          }

          Q:那么我們想執(zhí)行這個函數(shù)需要怎么做呢?A:如果想執(zhí)行它,就必須得調(diào)用它,并且還得給它傳參。

          const hh = sum(1,2)
          console.log(hh) // =>3

          自執(zhí)行函數(shù)呢?自執(zhí)行函數(shù)就是當它被定義出來,就會自動執(zhí)行的函數(shù)。不需要調(diào)用,傳參也很方便。就上面的函數(shù),用自執(zhí)行函數(shù)定義就是這樣:

          let total = 0 
          (function sum (a,b{
              return total = a + b
          })(1,2)
          console.log(total) // => 3

          所以,這就很有用處了。

          const myImage = (function(){
            // 創(chuàng)建一個img標簽
            let imgNode = document.createElement('img')
            // 將創(chuàng)建好的img標簽添加到body上
            document.body.appendChild(imgNode)
            // new一個Image實例
            let img = new Image()
            // 圖片資源加載完成后將地址設(shè)置給上面創(chuàng)建好的img標簽的src屬性
            img.onload = function() {
              imgNode.src = img.src
            }
            return {
              setSrc(src){
                // 首先將加載中的圖片設(shè)定給img的src屬性
                imgNode.src = '圖片加載中的圖片(可本地地址)'
                // 將傳入的地址緩存到上面創(chuàng)建的實例的src中
                img.src = src
              }
            }
          })()// 自執(zhí)行函數(shù)
          // 使用
          myImage.setSrc('https://www.baidu.com/img/bd_logo1.png?where=super')

          調(diào)戲面試官的一天就這么輕松愉快地結(jié)束了。當你面試后真的遇到了別忘記回來點個贊哦

          -End-

          最近有一些小伙伴,讓我?guī)兔φ乙恍?nbsp;面試題 資料,于是我翻遍了收藏的 5T 資料后,匯總整理出來,可以說是程序員面試必備!所有資料都整理到網(wǎng)盤了,歡迎下載!

          點擊??卡片,關(guān)注后回復(fù)【面試題】即可獲取

          在看點這里好文分享給更多人↓↓

          瀏覽 24
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  无码精品毛片免费视频 | 91丨PORNY丨成人蝌蚪 | 青娱乐在线视频网址 | 99黄色视频 | 女人18片毛片90分钟 |