vant2 选择器添加搜索和多选功能

个人笔记,欢迎指正,不喜勿喷

组件代码

<template>
  <div>
    <van-field
      readonly
      clickable
      type="textarea"
      rows="1"
      autosize
      :value="displayValue"
      :label="label"
      :placeholder="placeholder"
      @click="showPicker = true"
      :rules="rules"
    />

    <van-popup v-model="showPicker" position="bottom" v-if="!readonly">
      <van-search v-model="searchQuery" placeholder="搜索" />
      <van-picker
        :default-index="defaultIndex"
        show-toolbar
        :columns="formattedColumns"
        @confirm="onConfirm"
        @cancel="showPicker = false"
      />
    </van-popup>
  </div>
</template>

<script>
export default {
  name: "SearchablePicker",
  props: {
    readonly: {
      type: Boolean,
      default: false
    },
    defaultIndex: {
      type: Number,
      default: 0
    },
    value: {
      type: [Number, String, Array],
      default: () => [],
    },
    columns: {
      type: Array,
      required: true,
    },
    label: {
      type: String,
      default: "选择项",
    },
    placeholder: {
      type: String,
      default: "点击选择",
    },
    multiSelect: {
      type: Boolean,
      default: false,
    },
    valueKey: {
      type: String,
      default: "value", // 默认使用 'value' 作为选项的值
    },
    labelKey: {
      type: String,
      default: "name", // 默认使用 'name' 作为选项的标签
    },

    rules: {
      type: Array,
      default: () => []
    }
  },
  data() {
    return {
      searchQuery: "",
      showPicker: false,
      selectedValues: Array.isArray(this.value)
        ? [...this.value]
        : [this.value],
    };
  },
  computed: {
    displayValue() {
      const selectedTexts = this.columns
        .filter((item) =>
          this.multiSelect
            ? this.selectedValues.includes(item[this.valueKey])
            : item[this.valueKey] === this.value
        )
        .map((item) => item[this.labelKey]);
      return selectedTexts.join(", ");
    },
    formattedColumns() {
      let arr = [];
      if (this.searchQuery) {
        arr = this.columns.filter((option) => {
          return option[this.labelKey].includes(this.searchQuery);
        });
      } else {
        arr = this.columns;
      }

      return arr.map((item) => ({
        text: item[this.labelKey],
        value: item[this.valueKey],
      }));
    },
  },
  watch: {
    value: {
      immediate: true,
      handler(newValue, oldValue) {
        // console.log(newValue, oldValue, "dddddd")
        if(newValue?.length === oldValue?.length) return
        // console.log(newValue, "dddddd", newValue === oldValue)
        this.selectedValues = Array.isArray(newValue) ? [...newValue] : [newValue];
      }
    },
    selectedValues(val) {
      if (this.multiSelect) {
        this.$emit("input", val);
      }
    },
  },
  methods: {
    onConfirm(selected) {
      if (this.multiSelect) {
        const valueIndex = this.selectedValues.indexOf(selected.value);
        if (valueIndex === -1) {
          this.selectedValues.push(selected.value);
        } else {
          this.selectedValues.splice(valueIndex, 1);
        }
        this.$emit("input", [...this.selectedValues]);
      } else {
        this.$emit("input", selected.value);
        this.showPicker = false;
      }
    },
    confirmSelection() {
      this.$emit("input", [...this.selectedValues]);
      this.showPicker = false;
    },
  },
};
</script>

<style scoped>
</style>

使用方法

<searchable-picker
	 :default-index="4"
	 v-model="form.year"
	 :columns="yearColumns"
	 valueKey="time"
	 labelKey="time"
	 label="年度"
	 placeholder="点击选择时间"
	 :rules="[{ required: true, message: '请选择年度' }]"
	 :readonly="form.targetId !== '-1'"
/>
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值