<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>

          以級(jí)聯(lián)選擇器為例,聊聊數(shù)據(jù)量過(guò)大造成的頁(yè)面卡頓問(wèn)題

          共 4729字,需瀏覽 10分鐘

           ·

          2021-03-14 11:50

          背景

          ?

          列表、樹(shù)、級(jí)聯(lián)選擇都是用來(lái)展示“大量”、“相似度高”的數(shù)據(jù),它們都是需要在dom中生成大量的節(jié)點(diǎn),這就造成了數(shù)據(jù)量大造成頁(yè)面卡頓的原因,當(dāng)然以elementui為例,其實(shí)el-tree和el-cascader都對(duì)外提供了允許數(shù)據(jù)懶加載提供了接口。還是以級(jí)聯(lián)選擇器為例,僅僅是提供了父節(jié)點(diǎn)到子節(jié)點(diǎn)的懶加載,若子節(jié)點(diǎn)數(shù)據(jù)量大,那就的需要我們自己來(lái)二次封裝。下面就來(lái)簡(jiǎn)單實(shí)現(xiàn)一下這個(gè)二次封裝的懶加載。下面實(shí)現(xiàn)的組件僅僅考慮子節(jié)點(diǎn)數(shù)據(jù)量大的情況

          ?

          效果展示


          考慮因素

          ?
          • 我們暫時(shí)稱(chēng)一級(jí)菜單為「類(lèi)型」,二級(jí)菜單為「標(biāo)簽」
          • 初始化時(shí),我們?cè)O(shè)置一個(gè)固定的標(biāo)簽個(gè)數(shù)n,如果每個(gè)類(lèi)型大于等于n,則顯示個(gè)數(shù)為n,如果小于n則顯示已有的個(gè)數(shù)
          • 當(dāng)我們滾動(dòng)條滾動(dòng)到底部時(shí),繼續(xù)加載n個(gè)標(biāo)簽,直到加載完畢。
          • 加載完新的數(shù)據(jù)之后,要讓滾動(dòng)條停留到上次滾動(dòng)的位置
          • 假如我們?cè)O(shè)置了默認(rèn)全選,則要在懶加載的時(shí)候,加載出來(lái)的新標(biāo)簽也要設(shè)置為選擇狀態(tài)
          • 盡管首次渲染僅僅加載了部分標(biāo)簽,但是允許搜索的時(shí)候,范圍為所有的標(biāo)簽數(shù)據(jù)
          • 全選的時(shí)候要有一個(gè)標(biāo)識(shí)來(lái)告訴用戶(hù)現(xiàn)在是全選的狀態(tài)
          ?

          關(guān)鍵代碼

          在觸發(fā)每個(gè)「類(lèi)型」的click時(shí)候,需要為級(jí)聯(lián)面板綁定滾動(dòng)監(jiān)聽(tīng),并將當(dāng)前的類(lèi)型傳到滾動(dòng)回調(diào)。當(dāng)然因?yàn)榛卣{(diào)函數(shù)為同一個(gè),所以不會(huì)造成多次監(jiān)聽(tīng)的問(wèn)題。

          handleChange(value) {
              if (!this.lazy) {
                return
              }
              this.$nextTick(() => {
                const panel = document.querySelectorAll('.el-cascader-menu__wrap.el-scrollbar__wrap')
                const length = panel.length
                const currentPanel = panel[length-1]
                this.type = value[0]

                if (currentPanel) {
                  currentPanel.addEventListener('scroll'this.scrollCallback(currentPanel))
                }
              })
          },

          大部分的邏輯都在滾動(dòng)回調(diào)中

          scrollCallback(el) {
            return () => {
              const scrollTop = el.scrollTop
              const clientHeight = el.clientHeight
              const scrollHeight = el.scrollHeight

              // 若scrollTop + clientHeight === scrollHeight 則說(shuō)明滾動(dòng)條到達(dá)了底部
              if (scrollTop + clientHeight === scrollHeight) {
                const tmp = []
                // 當(dāng)前類(lèi)型下所有的選項(xiàng)
                const allOptions = this.allOptions.filter(options=>options.value === this.type)[0]?.children

                this.options.forEach(element => {
                  if (element.value === this.type) {

                    const optionLen = element.children.length-1
                    const allOptionsLen = allOptions.length-1

                    if (optionLen >= allOptionsLen) {
                      return
                    }

                    const loadsize = optionLen + this.loadSize
                    // 當(dāng)我們滾動(dòng)條滾動(dòng)到底部時(shí),繼續(xù)加載n個(gè)標(biāo)簽,直到加載完畢
                    const size = loadsize > allOptionsLen ? allOptionsLen : loadsize
                    for (var i=optionLen; i<=size; i++) {
                      tmp.push(allOptions[i])
                      if (this.isAllSelected) {
                        this.values.push([this.type, allOptions[i].value])
                      }
                    }
                    element.children.push(...tmp)
                  }
                })
                
                //加載完新的數(shù)據(jù)之后,要讓滾動(dòng)條停留到上次滾動(dòng)的位置
                setTimeout(() => {
                  el.scrollTop = scrollTop
                })
              }
            }
          }

          源碼與使用方式

          ?
          • 源碼
          • npm install cu-vue-cascader
          • import CuVueCascader from 'cu-vue-cascader'
          • vue.use(CuVueCascader)
          // 幾個(gè)重要的參數(shù)
          allOptions: array 所有的餐素
          selectAll:  boolean 默認(rèn)是否全選
          allSelectedClass: {} 全選時(shí)候的樣式
          lazy: boolean 是否開(kāi)啟子選項(xiàng)的懶加載
          loadSize: number 子選擇每次加載的條數(shù)
          ?


          瀏覽 349
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <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>
                  影音先锋国男人资源 | 九九国产视频 | 欧美性交手机在线 | 天天日天天撸 | 插逼视频网站大全 |