element-ui - 解决el-select数据量过大卡顿问题

解决el-select数据量过大卡顿问题


前言

当我们的下拉列表数据量过大时,初始化可能会有卡顿现象,我们可以通过滚动显示更多数据来解决这个问题。


一、el-select封装

// 控件名称  LargeDataSearchSelect
<tempalte>
  <div></div>
</tempalte>

<script>
export default {
  name: 'large-data-search-select',
  directives: {
    'el-select-loadmore': {
      bind(el, binding) {
        // 获取element-ui定义好的scroll盒子
        const SELECTWRAP_DOM = el.querySelector(
            '.el-select-dropdown .el-select-dropdown__wrap'
        )
        SELECTWRAP_DOM.addEventListener('scroll', function () {
          /**
           * scrollHeight 获取元素内容高度(只读)
           * scrollTop 获取或者设置元素的偏移值,常用于, 计算滚动条的位置, 当一个元素的容器没有产生垂直方向的滚动条, 那它的scrollTop的值默认为0.
           * clientHeight 读取元素的可见高度(只读)
           * 如果元素滚动到底, 下面等式返回true, 没有则返回false:
           * ele.scrollHeight - ele.scrollTop === ele.clientHeight;
           */
          const condition = this.scrollHeight - this.scrollTop <= this.clientHeight
          if (condition) binding.value()
        })
      }
    }
  },
  props: {
    selectProps: {
      type: Object,
      default: () => {
        return {
          options: [],
          rangeNumber: 100
        }
      },
      require: true
    },
    value: {
      type: String,
      default: ''
    }
  },
  data() {
    return {
      selectValue: '',
      rangeNumber: this.selectProps.rangeNumber || 100,
      options: [],
      originalData: []
    }
  },
  watch: {
    value: {
      handler(newVal) {
        this.selectValue = newVal
      },
      deep: true,
      immediate: true
    },

    selectProps() {

      this.init()
    }
  },

  created() {

    this.delayFilter = _.debounce((query)=>{
      this.filter(query)
    },500)
  },

  mounted() {

    this.$nextTick(() => {

      this.init()
    })
  },
  methods: {

    init() {

      this.originalData = this.selectProps.options
      this.initRenderOpions()
    },

    loadMore(n) {
      if (n < 8) this.rangeNumber = 10
      return () => (this.rangeNumber += 5) // 每次滚动到底部可以新增条数  可自定义
    },

    filter(query) {
      if (query) {
        let newOption = this.originalData.filter((item) =>
            item[this.selectProps.label || 'label'].includes(query)
        )

        if(newOption.length) {
          return this.options = newOption
        }
      }

      this.initRenderOpions()
    },

    selectChange() {

      this.$emit('updateChange', this.selectValue)
      this.initRenderOpions()
    },

    initRenderOpions() {
      let options = this.originalData.slice(0, this.rangeNumber)
      let index = -1

      if (_.size(this.selectValue)) {
        index = _.findIndex(options, (item)=>{
          return item.game_id === this.selectValue
        })

        if(index === -1) {
          let currentItem = _.find(this.originalData, (game)=>{
            return game.game_id === this.selectValue
          })

          if(currentItem) {
            options.unshift(currentItem)
          }
        }
      }

      this.options = options
    }
  },

  render() {
    return (
        <el-select
    {...this.$attrs}
    v-model={this.selectValue}
    placeholder={this.selectProps.placeholder || '请选择'}
    popper-append-to-body={false}
    clearable
    filterable
    filter-method={this.delayFilter}
    onChange={this.selectChange}
    v-el-select-loadmore:rangeNumber={this.loadMore(this.rangeNumber)}
        >
        {this.options.map((item, index) => {
            return (
                <el-option
                  key={item[this.selectProps.value || 'value']}
                  label={item[this.selectProps.label || 'label']}
                  value={item[this.selectProps.value || 'value']}
                 ></el-option>
          )
          })}
        </el-select>
  )
  }
}
</script>

二、使用

<template>
<!-- 原本的 el-select -->
<!--  <el-select class="extern-header-gamelist fl" size="small" v-model="gameId" filterable placeholder="请按游戏筛选查看"-->
<!--             @change="onChangeGameIdHandler">-->
<!--    <el-option v-for="(item, index) in gameList" :label="item.game_name" :value="item.game_id" :key="index"-->
<!--               style="width:217px;"></el-option>-->
<!--  </el-select>-->

  <!-- 使用自己封装的el-select -->
  <LargeDataSearchSelect class="extern-header-gamelist fl" size="small"
                  v-model="gameId"
                  :selectProps.sync="selectProps"
                  @updateChange="onChangeGameIdHandler"
  />
</template>

<script>
import util from '@/common/util'
import LargeDataSearchSelect from "@/components/large-data-search-select";
export default {
  name: "app",
  components: {
    LargeDataSearchSelect
  },
  data(){
    return {
      gameList: [],
      gameId: util.getGameId(),
    }
  },
  computed: {
    selectProps() {
      return {
        placeholder: '请按游戏筛选查看',
        options: _.clone(this.gameList),
        rangeNumber: 100,
        label: "game_name",
        value: "game_id"
      }
    },
  },
  created() {

    this.fetchGameList()
  },
  methods: {
    async fetchGameList() {
      let result;

      result = await IBOX.waxios({
        url: `${IBOX.config.baseURL}api/get_gs_games`,
        method: 'Get'
      })

      if(result && result.ret === 0 && _.isArray(result.data)) {

        this.gameList = _.map(result.data, (game) => {
          return {
            game_id: '' + game.game_id,
            game_name: `[${game.game_id}]${game.game_name}`
          }
        })
        IBOX.gameList = this.gameList;
        this.selectProps.options = _.clone(this.gameList);
        this.$store.commit('updateGameList', this.gameList)
      }else{

        this.$alert(staticData.requestFailMessage).then(()=>{

          this.fetchGameList()
        })
      }
    },

    onChangeGameIdHandler(gameId) {
      if(util.getGameId() !== gameId) {
        util.setGameId(gameId);
        this.$emit('change-game');
      }
    },
  }
}
</script>

总结

原文转载来自: 解决el-select数据量过大卡顿问题-记录贴

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用\[1\]和\[2\]中提到了使用this.$forceUpdate()来重新渲染el-select组件。这个方法可以在数据赋值后手动调用,强制组件重新渲染。在el-select组件上添加key属性,将其绑定到一个会动态变化的值上,比如后端返回的数据集合的长度,也可以解决样式不一致的问题。所以,如果在element-ui中使用el-select绑定函数时出现样式问题,可以尝试使用this.$forceUpdate()方法重新渲染组件,并在el-select上添加key属性绑定一个动态变化的值。 #### 引用[.reference_title] - *1* [element-ui 解决 el-select 设置默认值后无法切换选项](https://blog.csdn.net/weixin_44640323/article/details/122175514)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [element-ui 解决 el-select 设置初始默认值后切换选项无效问题](https://blog.csdn.net/sea9528/article/details/121403975)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [< element-UIel-select组件,下拉时内容无法显示滚动条 >](https://blog.csdn.net/MrWen2395772383/article/details/126159719)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值