最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

element select實(shí)現(xiàn)組件虛擬滾動(dòng)優(yōu)化

 更新時(shí)間:2023年04月11日 09:59:28   作者:WujieLi  
本文主要介紹了element select實(shí)現(xiàn)組件虛擬滾動(dòng)優(yōu)化,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

不知道大家在開(kāi)發(fā)過(guò)程中有沒(méi)有遇到這樣一個(gè)場(chǎng)景,后端接口一次性返回上千條數(shù)據(jù)(比如國(guó)家地區(qū)),接口不支持分頁(yè),不能篩選,只能前端自己通過(guò) select 組件全量渲染出來(lái)。這種渲染大量 DOM 的場(chǎng)景下會(huì)造成頁(yè)面非常卡頓,我在網(wǎng)上搜索了一下一般有兩種解決方案

最好的方案當(dāng)然時(shí)直接使用成熟的輪子,奈何我們的項(xiàng)目是 vue 2.7,所以只能借助支持 vue2 的虛擬滾動(dòng)組件 vue-virtual-scroll-list,自己封裝一個(gè) select 虛擬滾動(dòng)組件

組件實(shí)現(xiàn)

首先在項(xiàng)目中引入 vue-virtual-scroll-list

npm i vue-virtual-scroll-list

接下來(lái)開(kāi)發(fā)封裝虛擬滾動(dòng)組件,因?yàn)槭褂玫氖?vue2.7 版本,為了以后項(xiàng)目升級(jí) vue3,所以直接使用 composition api 的方式開(kāi)發(fā)。在 el-select 組件內(nèi)部引入安裝好的 vue-virtual-scroll-list,定義好組件的基礎(chǔ)結(jié)構(gòu),和需要傳入的 props 屬性

<template>
  <el-select
    v-model="value"
    v-bind="$atts"
    v-on="$listeners"
  >
    <virtual-scroll-list
      ref="virtualListRef"
    ></virtual-scroll-list>
  </el-select>
</template>

<script setup>
  import VirtualScrollList from 'vue-virtual-scroll-list'

  const props = defineProps({
    // 當(dāng)前
    value: {
      type: [String, Number],
      default: '',
    },
    // 下拉展示的 options
    options: {
      type: Array,
      default: () => [],
    },
    // label 鍵值
    labelKey: {
      type: String,
      default: 'label',
    },
    // value 鍵值
    valueKey: {
      type: String,
      default: 'value',
    },
  })

  const { value, options, labelKey, valueKey } = toRefs(props)

  const virtualListRef = ref(null)
</script>

根據(jù)官網(wǎng)文檔描述,有三個(gè)必填屬性,data-key, data-sources, data-component,我們可以直接選取 value 作為唯一的 data-key,data-sources 就是我們傳入的 options,data-component 需要我們將 el-option 封裝為一個(gè)獨(dú)立的組件

屬性是否必填默認(rèn)值類型描述
data-key必填String | Function虛擬滾動(dòng)列表每一項(xiàng)的唯一 id,如果是函數(shù)的話需要返回 string
data-sources必填Array[Object]虛擬滾動(dòng)的數(shù)據(jù)列表,每個(gè)數(shù)組項(xiàng)必須是對(duì)象,并且每個(gè)對(duì)象必須有一個(gè)唯一的屬性與 data-key 匹配
data-component必填Component虛擬滾動(dòng)每一項(xiàng)的渲染組件
keeps非必填30Number虛擬列表展示的真實(shí) DOM 的數(shù)量
extra-props非必填{}Object傳遞給子組件的額外參數(shù)

我們先將 el-option 封裝為一個(gè)獨(dú)立組件,需要注意的是 vue-virtual-scroll-list 默認(rèn)傳入是數(shù)組是 source,所以需要從 source 屬性中根據(jù) labelKey 和 valueKey 找到需要加載的 label 和 value

<template>
  <el-option 
    :key="value" 
    :label="label" 
    :value="value" 
    v-bind="$atts"
    v-on="$listeners"
   />
</template>

<script setup>
  import { computed, toRefs } from 'vue'

  const props = defineProps({
    source: {
      type: Object,
      default: () => {},
    },
    valueKey: {
      type: [String, Number],
      default: '',
    },
    labelKey: {
      type: String,
      default: '',
    },
  })

  const { source, valueKey, labelKey } = toRefs(props)

  const value = computed(() => source.value[valueKey.value])
  const label = computed(() => source.value[labelKey.value])
</script>

接著在父組件中引入封裝的 el-option 組件,這里我們?nèi)∶麨?OptionNode,然后傳入 data-key, data-sources, data-component 三個(gè)必填屬性,同時(shí)將 labelKey 和 valueKey 通過(guò) extra-props 屬性傳遞給子組件。vue-virtual-scroll-list 組件需要顯式設(shè)置列表的高度和滾動(dòng)條,不然在元素過(guò)多時(shí)會(huì)出現(xiàn)列表過(guò)長(zhǎng)的情況,同時(shí)為了配合項(xiàng)目,這里我將 keeps 屬性設(shè)置為 20,也就是只渲染 20 個(gè)真實(shí) DOM 節(jié)點(diǎn)

<template>
  <fe-select
    v-model="value"
    v-bind="$atts"
    v-on="$listeners"
  >
    <virtual-scroll-list
      ref="virtualListRef"
+     class="virtual-scroll-list"
+     :data-key="dataKey"
+     :data-sources="allOptions"
+     :data-component="OptionNode"
+     :keeps="20"
+     :extra-props="{
+       labelKey,
+       valueKey,
+     }"
    ></virtual-scroll-list>
  </fe-select>
</template>

<script setup>
  import { toRefs, ref, nextTick, computed, watch, onMounted } from 'vue'
  import VirtualScrollList from 'vue-virtual-scroll-list'
+ import OptionNode from './option-node.vue'

  const props = defineProps({
    value: {
      type: [String, Number],
      default: '',
    },
    options: {
      type: Array,
      default: () => [],
    },
    labelKey: {
      type: String,
      default: 'label',
    },
    valueKey: {
      type: String,
      default: 'value',
    },
  })

  const { value, options, labelKey, valueKey } = toRefs(props)

  const virtualListRef = ref(null)

+ const dataKey = ref(valueKey)
+ const allOptions = options.value
</script>

+ <style lang="scss" scoped>
+   .virtual-scroll-list {
+     height: 200px;
+     overflow: auto;
+   }
+ </style>

這個(gè)時(shí)候就可以初步實(shí)現(xiàn)虛擬列表滾動(dòng)的效果了,但由于虛擬滾動(dòng)僅渲染部分 DOM,所有還有兩個(gè)問(wèn)題需要考慮

  • 保存了選擇項(xiàng)后,再二次加載時(shí),需要顯示保存項(xiàng),這時(shí)需要從完整 options 中找到保存項(xiàng)并放在列表最上面
  • 篩選列表選項(xiàng)時(shí),需要從完整 options 找到符合要求的選項(xiàng)并加載,同時(shí)在關(guān)閉列表時(shí),需要重置列表

針對(duì)以上兩個(gè)問(wèn)題,我們引入一個(gè) currentOptions 記錄當(dāng)前的 options,通過(guò) remote-method 實(shí)現(xiàn)搜索效果,通過(guò) visible-change 事件實(shí)現(xiàn)重置列表。經(jīng)過(guò)優(yōu)化后的代碼如下

<template>
  <fe-select
    v-model="value"
+   filterable
+   remote
+   :remote-method="handleRemoteMethod"
    v-bind="$atts"
+   @visible-change="handleVisiableChange"
    v-on="$listeners"
  >
    <virtual-scroll-list
      ref="virtualListRef"
      class="virtual-scroll-list"
      :data-key="dataKey"
      :data-sources="currentOptions"
      :data-component="OptionNode"
      :keeps="20"
      :extra-props="{
        labelKey,
        valueKey,
      }"
    ></virtual-scroll-list>
  </fe-select>
</template>

<script setup>
  import { toRefs, ref, nextTick, computed, watch, onMounted } from 'vue'
  import VirtualScrollList from 'vue-virtual-scroll-list'
  import OptionNode from './option-node.vue'
+ import { cloneDeep, isNil } from 'lodash-es'

  const props = defineProps({
    value: {
      type: [String, Number],
      default: '',
    },
    options: {
      type: Array,
      default: () => [],
    },
    labelKey: {
      type: String,
      default: 'label',
    },
    valueKey: {
      type: String,
      default: 'value',
    },
  })

  const { value, options, labelKey, valueKey } = toRefs(props)

  const virtualListRef = ref(null)

  const dataKey = ref(valueKey)

+ // 當(dāng)前篩選的 options
+ const currentOptions = ref([])
+ // 全量 options
+ // 注意這里需要深拷貝
+ const allOptions = computed(() => cloneDeep(options.value))

+ onMounted(() => {
+   handleInitOptions(allOptions.value, value.value)
+ })

+ watch([value, options], ([newVal, newOptions], [_oldVal, oldOptions]) => {
+   // 異步加載 options 時(shí),如果 value 有值,需要將 value 對(duì)應(yīng)的 option 放在第一位
+   if ((!isNil(newVal) || newVal !== '') && newOptions.length > 0 && oldOptions.length === 0) {
+     handleInitOptions(newOptions, newVal)
+   }
+ })

+ /**
+  * @description 因?yàn)?DOM 不是全量加載,所以需要手動(dòng)處理
+  */
+ function handleRemoteMethod(query) {
+   if (query !== '') {
+     currentOptions.value = allOptions.value.filter((item) => {
+       return item[labelKey.value].includes(query)
+     })
+   } else {
+     currentOptions.value = allOptions.value
+   }
+ }

+ function handleVisiableChange(val) {
+   // 隱藏下拉框時(shí),重置數(shù)據(jù)
+   if (!val) {
+     virtualListRef.value && virtualListRef.value.reset()
+     nextTick(() => {
+       currentOptions.value = allOptions.value
+     })
+   }
+ }

+ /**
+  * @description 異步加載 options 時(shí),如果 value 有值,需要將 value 對(duì)應(yīng)的 option 放在第一位
+  */
+ function handleInitOptions(allOptions, value) {
+   const existOption = allOptions.find((item) => {
+     return item[valueKey.value] === value
+   })
+   if (existOption) {
+     currentOptions.value.push(existOption)
+   }

+   currentOptions.value.push(
+     ...allOptions.filter((item) => {
+       return item[valueKey.value] !== value
+     })
+   )
+ }
</script>

<style lang="scss" scoped>
  .virtual-scroll-list {
    height: 200px;
    overflow: auto;
  }
</style>

總結(jié)

最后我們來(lái)看一下最終實(shí)現(xiàn)效果,可以看到在實(shí)際選項(xiàng)有 10000 個(gè)情況下,每次渲染出來(lái)的 DOM 只有 20 個(gè),而且不論是滾動(dòng)還是查詢都絲滑流暢,完成的組件封裝代碼和示例我也放在 github 上(鏈接

到此這篇關(guān)于element select實(shí)現(xiàn)組件虛擬滾動(dòng)優(yōu)化的文章就介紹到這了,更多相關(guān)element select組件虛擬滾動(dòng)優(yōu)化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Element Input輸入框的使用方法

    Element Input輸入框的使用方法

    這篇文章主要介紹了Element Input輸入框的使用方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • Vue之Computed依賴收集與更新原理分析

    Vue之Computed依賴收集與更新原理分析

    這篇文章主要介紹了Vue之Computed依賴收集與更新原理分析,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • Vue中tab欄切換的簡(jiǎn)單實(shí)現(xiàn)

    Vue中tab欄切換的簡(jiǎn)單實(shí)現(xiàn)

    本文主要介紹了Vue中tab欄切換的簡(jiǎn)單實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-07-07
  • Vue3實(shí)現(xiàn)密碼加密登錄的示例代碼

    Vue3實(shí)現(xiàn)密碼加密登錄的示例代碼

    現(xiàn)在,很多登陸表單都會(huì)使用密碼加密,為登錄安全,登錄表單輸入密碼,會(huì)加密后傳入后臺(tái),本文就來(lái)介紹一下Vue3實(shí)現(xiàn)密碼加密登錄的示例代碼,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-02-02
  • vue.js默認(rèn)路由不加載linkActiveClass問(wèn)題的解決方法

    vue.js默認(rèn)路由不加載linkActiveClass問(wèn)題的解決方法

    這篇文章主要給大家介紹了關(guān)于vue.js默認(rèn)路由不加載linkActiveClass問(wèn)題的解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。
    2017-12-12
  • vue中promise的使用及異步請(qǐng)求數(shù)據(jù)的方法

    vue中promise的使用及異步請(qǐng)求數(shù)據(jù)的方法

    這篇文章主要介紹了vue中promise的使用及異步請(qǐng)求數(shù)據(jù)的方法,文章給大家較詳細(xì)的介紹了遇到的問(wèn)題及解決方法,需要的朋友可以參考下
    2018-11-11
  • vue3+arco design通過(guò)動(dòng)態(tài)表單方式實(shí)現(xiàn)自定義篩選功能

    vue3+arco design通過(guò)動(dòng)態(tài)表單方式實(shí)現(xiàn)自定義篩選功能

    這篇文章主要介紹了vue3+arco design通過(guò)動(dòng)態(tài)表單方式實(shí)現(xiàn)自定義篩選,本文主要實(shí)現(xiàn)通過(guò)動(dòng)態(tài)表單的方式實(shí)現(xiàn)自定義篩選的功能,用戶可以自己添加篩選的項(xiàng)目,篩選條件及篩選內(nèi)容,需要的朋友可以參考下
    2024-05-05
  • 解決vue項(xiàng)目使用font-awesome,build后路徑的問(wèn)題

    解決vue項(xiàng)目使用font-awesome,build后路徑的問(wèn)題

    今天小編就為大家分享一篇解決vue項(xiàng)目使用font-awesome,build后路徑的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-09-09
  • Vue中$forceUpdate()的使用方式

    Vue中$forceUpdate()的使用方式

    這篇文章主要介紹了Vue中$forceUpdate()的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • Vue之計(jì)算屬性詳解

    Vue之計(jì)算屬性詳解

    這篇文章主要為大家介紹了Vue的計(jì)算屬性,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2021-11-11

最新評(píng)論

寿光市| 岚皋县| 三亚市| 鹤岗市| 遂溪县| 斗六市| 无棣县| 丽江市| 修文县| 麻栗坡县| 沽源县| 邮箱| 沧州市| 西贡区| 宝兴县| 鄱阳县| 阜宁县| 锡林郭勒盟| 平乡县| 察哈| 临清市| 内丘县| 桂平市| 宜昌市| 德钦县| 满洲里市| 岫岩| 微山县| 乌鲁木齐市| 张家口市| 山东省| 海林市| 冕宁县| 安泽县| 河曲县| 五家渠市| 仪征市| 雷山县| 宁南县| 仙桃市| 肇州县|