Implementing Remote Search and Dynamic Loading with Vue and Element UI's el-select

When using Element UI's el-select, if there are too many option, loading all at once can cause page lag and white screen on dropdown click. We can implement dynamic loading with a custom directive.

First, define a global diretcive in main.js:

Vue.directive('infinite-scroll', {
  bind(el, binding) {
    const scrollContainer = el.querySelector('.el-select-dropdown .el-select-dropdown__wrap');
    scrollContainer.addEventListener('scroll', function () {
      const isBottom = this.scrollHeight - this.scrollTop <= this.clientHeight;
      if (isBottom) {
        binding.value();
      }
    });
  }
});

Then, create a reusable component named RemoteSelect.vue:

<template>
  <el-select
    size="small"
    multiple
    v-bind="$attrs"
    v-infinite-scroll="loadMore"
    collapse-tags
    filterable
    :clearable="clearableFlag"
    :placeholder="placeholder"
    :filter-method="handleFilter"
    v-model="value"
    @change="onChange"
    @visible-change="handleVisibility"
  >
    <el-option
      v-for="item in items"
      :key="item.number"
      :value="item.number"
      :label="item.name"
    >
      {{ item.name }}
    </el-option>
  </el-select>
</template>

<script>
import _ from 'lodash';
import { api } from '@/apis';

export default {
  model: {
    prop: 'inputValue',
    event: 'change',
  },
  props: {
    clearableFlag: {
      type: Boolean,
      default: false,
    },
    inputValue: {
      type: [Array, String],
      default: () => [],
    },
    placeholder: {
      type: String,
      default: '请选择',
    },
    size: {
      type: String,
      default: 'medium',
    },
  },
  watch: {
    inputValue(newVal) {
      this.value = newVal;
    },
  },
  data() {
    return {
      value: '',
      items: [],
      total: 0,
      searchParams: {
        name: '',
        currentPage: 1,
        pageSize: 20,
      },
      isFirstLoad: true,
    };
  },
  methods: {
    loadMore() {
      const { pageSize, currentPage } = this.searchParams;
      if (pageSize * currentPage < this.total) {
        this.searchParams.currentPage++;
        this.fetchItems();
      }
    },
    fetchItems() {
      // Example: replace with actual API call
      // api.getList(this.searchParams).then((res) => {
      //   if (res.data.success) {
      //     this.items = [...this.items, ...res.data.data.list];
      //     this.total = res.data.data.total;
      //   }
      // });
    },
    handleFilter: _.debounce(function (val) {
      this.searchParams.name = val;
      this.searchParams.currentPage = 1;
      this.items = [];
      this.total = 0;
      this.fetchItems();
    }, 500),
    handleVisibility(visible) {
      if (!visible) {
        if (this.searchParams.name !== '') {
          this.handleFilter('');
        }
      } else if (this.isFirstLoad) {
        this.isFirstLoad = false;
        this.fetchItems();
      }
    },
    onChange(val) {
      this.$emit('change', val);
    },
  },
};
</script>

Finally, use the component in your page:

<template>
  <RemoteSelect
    placeholder="请输入"
    v-model="keyword"
    @change="handleSearch"
  />
</template>

<script>
import RemoteSelect from '@/components/RemoteSelect.vue';

export default {
  components: {
    RemoteSelect,
  },
  data() {
    return {
      keyword: '',
    };
  },
  methods: {
    handleSearch() {
      // search logic
    },
  },
};
</script>

Try it in your project!

Tags: Vue.js Element UI el-select dynamic loading remote search

Posted on Thu, 04 Jun 2026 16:16:06 +0000 by bri0987