vant4下拉选择器多选的封装

本来想从网上找一个封装好的直接用,没找到(可能是我没怎么找吧),然后就自己简单封装了一下,如有不好的地方,希望各位大佬多多指导(欢迎多多评论)

 效果图(支持通过关键字搜索)

1.子组件

<template>
  <div>
    <van-field
      :modelValue="selectedItems"
      readonly
      clearable
      required
      :label="label"
      :name="name"
      v-bind="$attrs"
      @click="showPopup"
    />
    <van-popup
      v-model:show="popupVisible"
      position="bottom"
      class="popup-style"
    >
      <div>
        <div class="pad10 flex-between showMultipleButton">
          <van-button plain size="normal" @click="cancelSelection"
            >取消</van-button
          >
          <!-- 标题 -->
          <div class="bold">
            {{ label }}
          </div>
          <van-button
            plain
            type="primary"
            size="normal"
            @click="confirmSelection"
            >确定</van-button
          >
        </div>
        <van-field
          left-icon="search"
          v-model.trim="searchKeyword"
          clearable
          placeholder="请输入搜索关键字"
        ></van-field>
      </div>
      <div class="checkbox-style">
        <van-checkbox-group v-model="checkedValue">
          <van-cell-group>
            <van-cell
              v-for="(item, index) in filteredColumns"
              :key="index"
              :title="item.text"
              clickable
              @click="toggle(index)"
            >
              <template #right-icon>
                <van-checkbox
                  :name="item.value"
                  :ref="(el) => (checkboxRefs[index] = el)"
                  @click.stop
                />
              </template>
            </van-cell>
          </van-cell-group>
        </van-checkbox-group>
      </div>
    </van-popup>
  </div>
</template>

<script setup>
import { onMounted, ref, onBeforeUpdate, computed, nextTick } from "vue";

const props = defineProps({
  options: {
    type: Array,
    required: true,
  },
  modelValue: {
    type: Array,
    default: () => [],
  },
  label: String,
  name: String,
});

const emit = defineEmits(["update:modelValue"]);

const selectedItems = ref([]);
const popupVisible = ref(false);
const searchKeyword = ref(null);
const checkboxRefs = ref([]);
const checkedValue = ref([]);
onMounted(() => {
  nextTick(() => {
    reShow();
  });
});
// 异步数据回显方法
const findTextsByValues = (valuesToFind, data) => {
  return valuesToFind.map((value) => {
    const foundItem = data.find((item) => item.value === value);
    return foundItem ? foundItem.text : null;
  });
};

const reShow = () => {
  if (props.modelValue) {
    if (Array.isArray(props.options)) {
      selectedItems.value = findTextsByValues(props.modelValue, props.options);
    }
  }
};
const toggle = (index) => {
  checkboxRefs.value[index].toggle();
};
onBeforeUpdate(() => {
  checkboxRefs.value = [];
});
// 弹出层
const showPopup = () => {
  checkedValue.value = props.modelValue;
  popupVisible.value = true;
};
// 取消
const cancelSelection = () => {
  popupVisible.value = false;
};
// 确定
const confirmSelection = () => {
  selectedItems.value = findTextsByValues(checkedValue.value, props.options);
  emit("update:modelValue", checkedValue.value);
  popupVisible.value = false;
};
// 弹出层搜索框
const filteredColumns = computed(() => {
  return props.options.filter((item) => {
    return item.text.includes(searchKeyword.value);
  });
});
</script>

<style scoped>
.popup-style {
  height: 21.25rem;
}
.showMultipleButton {
  padding-bottom: 0;
}

.showMultipleButton .van-button {
  border: 0;
}
.flex-between {
  padding: 10px;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.bold {
  font-weight: bold;
  color: #444;
}
.checkbox-style {
  height: 220px;
  overflow-y: auto;
}
</style>

2.父组件 

<template>
    <VanMultipleSelect
      :options="dataList"
      v-model="form.selectedValue"
      label="城市"
      :name="form.selectedValue"
      placeholder="请选择城市"
      error-message-align="right"
      input-align="right"
      :rules="[{ required: true, message: '请选择城市' }]"
    ></VanMultipleSelect>

</template>
<script setup lang="ts">
import VanMultipleSelect from "./components/VanMultipleSelect.vue";
import { ref } from "vue";

const dataList = ref([
  { text: "杭州", value: "Hangzhou" },
  { text: "宁波", value: "Ningbo" },
  { text: "温州", value: "Wenzhou" },
  { text: "绍兴", value: "Shaoxing" },
  { text: "湖州", value: "Huzhou" },
]);
const form = ref({
  selectedValue: [],
});
</script>
  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值