vue3+element下拉多选框组件

vue3+element下拉多选框组件_第1张图片
vue3+element下拉多选框组件_第2张图片

<!-- 下拉多选 -->
<template>
  <div class="select-checked">
    <el-select v-model="selected" :class="{ all: optionsAll, hidden: selectedOptions.data.length < 2 }" multiple
      placeholder="请选择" :popper-append-to-body="false" collapse-tags popper-class="select-popper">
      <template v-if="selectedOptions.data.length > 1" #prefix>
        <div class="multi">(多选) x {{ selectedOptions.data.length }}</div>
      </template>
      <el-option class="multiple" :value="item.value" :label="item.label" v-for="(item, key) in optionsData.data"
        :key="key">
        <el-checkbox v-model="item.check" @change="handleTaskItemChange(item)" style="width: 100%;">
          {{ item.label }}
        </el-checkbox>
      </el-option>
      <div class="is-all">
        <div @click="handleOptionsAllChange(true)">全选</div>
        <div @click="handleOptionsAllChange(false)">反选</div>
      </div>
    </el-select>
  </div>
</template>


<script setup>
import { ref, reactive, computed, watch, defineProps, onMounted } from 'vue'

let props = defineProps({
  options: {
    type: Array,
    required: true
  }
})

let optionsData = reactive({ data: [] })

let selectedOptions = reactive({ data: [] })

let optionsAll = ref(false)

const emit = defineEmits(['selected']);

watch(() => props.options, (newVal) => {
  optionsData.data = newVal;
  let checkedData = newVal.filter((item) => item.check);
  selectedOptions.data = checkedData.map((item) => item.value);
  optionsAll.value = checkedData.length === newVal.length;
}, { immediate: true })

onMounted(() => {
  // 在控件载入时触发父级的selected方法
  emit('selected', selectedOptions.data);
})

const selected = computed({
  get() {
    return selectedOptions.data.length > props.options.length ? [''] : selectedOptions.data;
  },
  set(value) {
    selectedOptions.data = value;
  }
})

const handleOptionsAllChange = (isAll) => {
  optionsData.data.forEach((elm) => {
    elm.check = isAll;
  });
  selectedOptions.data = isAll ? optionsData.data.map((item) => item.value) : [];
  emit('selected', selectedOptions.data);
}

const handleTaskItemChange = (item) => {
  if (!item.check) {
    selectedOptions.data = selectedOptions.data.filter((value) => value !== item.value);
  } else {
    selectedOptions.data.push(item.value);
  }
  optionsAll = selectedOptions.data.length === optionsData.data.length;
  emit('selected', selectedOptions.data);
}

</script>

<style lang="scss">
.select-checked {
  width: 420px;
  height: 30px;

  .el-input {
    width: 420px;
    height: 30px;
  }

  // tag删除图标
  .el-tag__close,
  .el-icon-close {
    display: none;
  }

  // 标签tag背景
  .el-tag.el-tag--info {
    background: transparent;
    border: 0;
    display: none;
  }

  // 第一个显示名称

  .hidden {
    .el-tag.is-closable.el-tag--default {
      display: block;
      line-height: 30px;
      padding-left: 15px;
      font-weight: 400;
      color: #333333;
    }
  }
}

.is-all {
  display: flex;

  div {
    cursor: pointer;
    margin: 6px 10px;
    transition: 0.2s;

    &:hover {
      opacity: .7;
    }
  }
}

.multi {
  font-size: 12px;
  font-weight: 400;
  color: #333333;
}
</style>
<style>
.el-select-dropdown.is-multiple.el-select-dropdown__item.selected::after {
  content: none;
}
</style>

使用:

<selectMulti :options="options" @selected="selected"></selectMulti>


let options = [
  {
    value: '001',
    label: '黄金糕',
    check: false
  },
  {
    value: '002',
    label: '双皮奶',
    check: false
  },
  {
    value: '003',
    label: '蚵仔煎',
    check: false
  },
  {
    value: '004',
    label: '龙须面',
    check: false
  },
  {
    value: '005',
    label: '北京烤鸭',
    check: false
  }
]


const selected = (value) => {
  console.log(value);
}

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