vue2+ant-design-vue a-select component secondary packaging (supports single selection/multiple selection to add all selections/pagination (multiple selections across pages)/custom label)

1. Renderings

2. Parameter configuration

1. Code example

<t-antd-select
  v-model="selectVlaue"
  :optionSource="stepList"
  @change="selectChange"
/>

2. Configuration parameters (Attributes) inherit a-select Attributes

Parameter Description Type Default value
v-model Bind value boolean / string / number/Array
mode Set ‘multiple”tags’ multi-selection (display all selection ) String
optionSource Drop-down data source Array
width select width (can set percentage or px) String 100%
customLabel Whether to customize the drop-down label String
valueKey In the passed option array, the key value key to be used as the final selection item String ‘key’
labelKey In the passed option array, the key value name to be displayed as the item String ‘label’
isShowPagination Whether to display paging (paging does not display the all-select box) Boolean false
paginationOption Pagination configuration item Object

2-1. PaginationOption configuration parameters (Attributes) inherit a-pagination Attributes

Parameter Description Type Default value
current Current page number number 1
pageSize Number of items displayed on each page number 6
total Total number of entries number 0
bind Inherit a-pagination attribute Object

3. Inherit a-select & amp; & amp;a-pagination events

Event name Description Return value
current-change Current page number Currently selected page number

3. Source code

<template>
  <div @mousedown="e => {
    e.preventDefault()
    selectOpen = true
  }" ref="main">
    <a-select
      class="t_select"
      v-model="childSelectedValue"
      :style="{width: width||'100%'}"
      :placeholder="placeholder"
      :open="selectOpen"
      @select="handleSelect"
      v-bind="attrs"
      v-on="$listeners"
      :mode="mode"
    >
      <template v-for="(index, name) in $slots" v-slot:[name]>
        <slot :name="name" />
      </template>
      <template v-for="(index, name) in $scopedSlots" v-slot:[name]="data">
        <slot :name="name" v-bind="data"></slot>
      </template>
      <div slot="dropdownRender" slot-scope="menu">
        <a-checkbox
          v-if="mode & amp; & amp;!isShowPagination"
          :checked="selectChecked"
          @change="selectAll"
          class="all_checkbox"
        >Select all</a-checkbox>
        <v-nodes :vnodes="menu" />
        <div class="t_select__pagination" v-if="isShowPagination">
          <a-pagination
            :page-size.sync="paginationOption.pageSize"
            v-model="paginationOption.current"
            :total="paginationOption.total"
            @change="currentChange"
            v-bind="{
            size:'small',
            'hide-on-single-page':true,
            'showQuickJumper': true,
            ...$attrs,
            ...paginationOption.bind,
          }"
            v-on="$listeners"
          />
        </div>
      </div>
      <a-select-option
        v-for="(item,index) in optionSource"
        :key="index"
        :value="item[valueKey]"
      >{<!-- -->{customLabel?customLabelHandler(item):item[labelKey]}}</a-select-option>
    </a-select>
  </div>
</template>
<script>
export default {<!-- -->
  name: 'TAntdSelect',
  components: {<!-- -->
    VNodes: {<!-- -->
      functional: true,
      render: (h, ctx) => ctx.props.vnodes
    }
  },
  props: {<!-- -->
    value: {<!-- -->
      type: [String, Number, Array, Boolean, Object]
    },
    //Multiple selection 'multiple'
    mode: {<!-- -->
      type: String
    },
    placeholder: {<!-- -->
      type: String,
      default: 'Please select'
    },
    //Select box width
    width: {<!-- -->
      type: String
    },
    // Whether to customize the drop-down label
    customLabel: {<!-- -->
      type: String
    },
    // In the option array passed in, the key value key to be used as the final selection item
    valueKey: {<!-- -->
      type: String,
      default: 'key'
    },
    // In the option array passed in, the key value name to be displayed as the item
    labelKey: {<!-- -->
      type: String,
      default: 'label'
    },
    // Drop-down box component data source
    optionSource: {<!-- -->
      type:Array
    },
    // Whether to display pagination
    isShowPagination: {<!-- -->
      type: Boolean,
      default: false
    },
    //Paging configuration items
    paginationOption: {<!-- -->
      type: Object,
      default: () => {<!-- -->
        return {<!-- -->
          pageSize: 6, //Number of items displayed on each page
          current: 1, // current page
          total: 0 //Total number of items
        }
      }
    }
  },
  data() {<!-- -->
    return {<!-- -->
      selectOpen: false
    }
  },
  computed: {<!-- -->
    childSelectedValue: {<!-- -->
      get() {<!-- -->
        return this.value || undefined
      },
      set(val) {<!-- -->
        this.$emit('input', val)
      }
    },
    attrs() {<!-- -->
      return {<!-- -->
        allowClear: true,
        showSearch: true,
        ...this.$attrs
      }
    },
    selectChecked: {<!-- -->
      get() {<!-- -->
        return this.childSelectedValue?.length === this.optionSource?.length
      },
      set(val) {<!-- -->
        // console.log('set', val)
        this.$emit('input', val)
      }
    }
  },
  mounted() {<!-- -->
    document.addEventListener('click', this.bodyCloseMenus)
  },
  beforeDestroy() {<!-- -->
    document.removeEventListener('click', this.bodyCloseMenus)
  },
  methods: {<!-- -->
    // Click on the empty area
    bodyCloseMenus(e) {<!-- -->
      if (this.$refs.main & amp; & amp; !this.$refs.main.contains(e.target)) {<!-- -->
        if (this.selectOpen == true) {<!-- -->
          this.selectOpen = false
        }
      }
    },
    // Click to select all
    selectAll(val) {<!-- -->
      const options = JSON.parse(JSON.stringify(this.optionSource))
      if (val.target.checked) {<!-- -->
        this.childSelectedValue = options?.map(item => {<!-- -->
          return item[this.valueKey]
        })
        setTimeout(() => {<!-- -->
          this.$emit('change', this.childSelectedValue)
        }, 0)
      } else {<!-- -->
        this.childSelectedValue = null
      }
      this.selectOpen = false
    },
    handleSelect(value, option) {<!-- -->
      if (value) {<!-- -->
        this.selectOpen = false
      }
      this.$emit('select', value, option)
    },
    // switch pagination
    currentChange(val) {<!-- -->
      // console.log('Switch paging', val)
      if (!this.mode) {<!-- -->
        this.childSelectedValue = null
      }
      setTimeout(() => {<!-- -->
        this.selectOpen = true
      }, 0)
      this.$emit('current-change', val)
    },
    // Custom label display
    customLabelHandler(item) {<!-- -->
      // eslint-disable-next-line no-eval
      return eval(this.customLabel)
    }
  }
}
</script>
<style lang="scss">
.all_checkbox {<!-- -->
  margin-left: 12px;
  margin-top: 5px;
}
</style>

4. Component address

gitHub component address

gitee code cloud component address

5. Related articles

Encapsulate basic component documents again based on ElementUi

Encapsulate basic component documents again based on ant-design-vue

vue3 + ts re-encapsulates basic component documents based on Element-plus