Ant Design Vue3 下拉框封装组件(全选,全不选)功能

Ant Design Vue3 下拉框封装组件(全选,全不选)功能

hooks文件 (filterSlots.js)

import { ref, useSlots } from 'vue'

/**
 * 过滤出父组件正在使用的插槽
 * @param {*} slotList
 * @returns
 */
export function useFilterSlots(slotList) {
    const getSlotList = ref([])
    const slotsNames = Object.keys(useSlots())
    const slots = slotList.filter(item => slotsNames.includes(item))
    slots.length && (getSlotList.value = slots)
    return {
        getSlotList
    }
}

封装下拉框组件

<template>
    <a-select
        showArrow
        :getPopupContainer="triggerNode => triggerNode.parentNode"
        v-bind="$attrs"
        :mode="mode"
        :style="style"
        :placeholder="placeholder"
        :max-tag-count="maxTagCount"
        :dropdown-class-name="computedDropdownClassName"
        :filter-option="handleFilterOption"
        :field-names="fieldNames"
        @change="handleChange"
    >
        <template v-if="mode === 'multiple'" #dropdownRender="{ menuNode: menu }">
            <div v-if="buttons" class="operation-buttons">
                <a-button type="primary" class="select-all" @click="handleSelect(true)">全选a-button>
                <a-button @click="handleSelect(false)">取消a-button>
            div>

            <v-nodes :vnodes="menu" />
        template>

        <template v-for="(slotItem, index) in getSlotList" :key="index" #[slotItem]="slotsParams">
            <slot :name="slotItem" :slotsParams="slotsParams">slot>
        template>
    a-select>
template>

<script>
import { defineComponent } from 'vue'
export default defineComponent({
    components: {
        VNodes: (_, { attrs }) => {
            return attrs.vnodes
        }
    }
})
script>

<script setup>
import { computed, useAttrs } from 'vue'
import { useFilterSlots } from '../hooks/filterSlots.js'

/** props */
const attrs = useAttrs()
const props = defineProps({
    mode: {
        type: String,
        default: 'multiple'
    },

    style: {
        type: Object,
        default: { minWidth: '200px', maxWidth: '500px' }
    },

    placeholder: {
        type: String,
        default: ''
    },
    // 最多显示多少个 tag
    maxTagCount: {
        type: Number,
        default: 1
    },
    // 自定义节点 label、value、options 的字段
    fieldNames: {
        type: Object,
        default: () => ({ label: 'label', value: 'value' })
    },

    onChange: {
        type: Function
    },
    // 是否需要按钮
    buttons: {
        type: Boolean,
        default: true
    }
})

/** state */
const slotList = [
    'clearIcon',
    'dropdownRender',
    'maxTagPlaceholder',
    'menuItemSelectedIcon',
    'notFoundContent',
    'option',
    'placeholder',
    'removeIcon',
    'suffixIcon',
    'tagRender',
    'label'
]
const { getSlotList } = useFilterSlots(slotList)

/** computed */
const computedDropdownClassName = computed(() =>
    props.mode === 'multiple' ? 'ant-select-multiple-dropdown' : 'ant-select-dropdown'
)

// 计算所有options的值
const computedAllOptionValue = computed(() => {
    const { options } = attrs
    const { value } = props.fieldNames

    if (options) {
        return options.map(item => item[value])
    }
})

/** methods */
const handleFilterOption = (inputValue, option) => {
    const { label } = props.fieldNames
    return option[label].toLowerCase().includes(inputValue.toLowerCase())
}

const emits = defineEmits(['update:value'])

const handleChange = (value, option) => {
    emits('update:value', value)
    let { onChange } = props
    onChange && onChange(value, option)
}

// 全选或取消全选
const handleSelect = selectType => {
    const { value } = attrs
    selectType ? value.push(...computedAllOptionValue.value) : value.splice(0, value.length)
    let uniqueValue = [...new Set(value)]
    emits('update:value', uniqueValue)
    let { onChange } = props
    onChange && onChange(uniqueValue)
}
script>

<style scoped lang="less">
.ant-select ::v-deep {
    .ant-select-selector {
        height: 32px;
    }
}

.ant-select-multiple-dropdown {
    .operation-buttons {
        padding: 2px 12px 8px;
        display: flex;
        justify-content: center;

        .ant-btn {
            width: 50%;
            height: 30px;
            line-height: normal;
        }

        .select-all {
            margin-right: 15px;
        }
    }
}
style>

案例使用


<template>
  <div>
   <CustomSelect
      v-model:value="dateType" 
      :placeholder="请选择"
      mode="multiple"
      :options="dateTypeOptions"
      allowClear
      showArrow />
  div>
template>
<script>
// 引入组件
import CustomSelect from '@/components/select'
import { ref } from 'vue'

export default defineComponent({
    components: {
        CustomSelect
    },
     setup() {
       const dateType= ref([])
       const dateTypeOptions = ref([
        {
          label: '1',
          value: 1
        },
        {
         label: '3',
         value: 3
        },
        { 
         label: '2',
         value: 2
       }
    ])
 return {
     dateTypeOptions,
     dateType
    }
  }
})
script>

你可能感兴趣的:(javascript,vue.js,前端框架)