vue3.x vant 实现select效果 单选

由于vant移动端组件中,没有提供select组件。下面我封装一个支持可模糊搜素远程搜素select选择器
效果如下:
在这里插入图片描述
在这里插入图片描述
Select Attributes
在这里插入图片描述

在这里插入图片描述

1.封装组件(vanFieldSelectPicker)

<template>
  <van-popup teleport="body" v-model:show="state.showPicker" position="bottom">
    <div class="van-picker__toolbar">
      <button type="button" class="van-picker__cancel" @click="state.showPicker = false">取消</button>
      <div class="van-ellipsis van-picker__title">{{ $attrs.title }}</div>
      <button type="button" class="van-picker__confirm" @click="confirmClick">确认</button>
    </div>
    <div class="van-field-box">
      <van-field
        v-if="props.isSearch"
        v-model="state.searchVal"
        input-align="left"
        :placeholder="$attrs.placeholder || '搜索'"
        @update:model-value="inputChange"
      />
      <van-loading  size="30px" vertical v-if="loading">加载中...</van-loading>
      <van-empty image="search" v-if="state.columns.length == 0 && !loading" description="" />
      <van-cell-group v-else>
        <van-cell
          :class="{ selected: item[options.value] == state.selectItem.value }"
          v-for="(item, index) in state.columns"
          :key="item[options.value]"
          :title="item[options.label]"
          clickable
          @click="cellClick(item)"
        >
          <template #right-icon>
            <van-icon style="display: flex !important;justify-content: center;align-items: center;" v-if="item[options.value] == state.selectItem.value" name="success" />
          </template>
        </van-cell>
      </van-cell-group>
    </div>
  </van-popup>
</template>

<script setup>
import { reactive, watch, computed } from "vue";
import { debounce } from "lodash-es";
const emit = defineEmits(["cellClick", "remoteMethed", "confirm", "update:modelValue", "update:show"]);
//props
const props = defineProps({
  columns: Array,
  remote: Boolean,
  loading: Boolean,
  modelValue: String,
  show: Boolean,
  options: {
    type: Object,
    default: () => {
      return { label: "label", value: "value" };
    },
  },
  //是否支持搜索
  isSearch: {
    type: Boolean,
    default: false,
  },
});
//data响应式数据
const state = reactive({
  selectItem: {}, //选中的选项
  showPicker: false,
  searchVal: "", //输入框value值
  columns: [], //数据
});
//确认点击
const confirmClick = () => {
  emit("update:show", false);
  emit("confirm", state.selectItem);
};
//选项的点击
const cellClick = (item) => {
  //已经选中的,再次点击不处理
  // if (item.value == props.selectItem.value) return;
  state.selectItem = item;
  emit("cellClick", item);
};
//防抖处理 模糊搜索value值改变触发
const inputChange = debounce(() => {
  //获取远程数据
  if (props.remote) {
    emit("remoteMethed", state.searchVal);
    return;
  }
  //获取所有的选项
  if (!state.searchVal) {
    state.columns = props.columns;
  } else {
    state.columns = props.columns.filter((item) => item[props.options.label].indexOf(state.searchVal) > -1);
  }
},500);
//展示/隐藏处理
state.showPicker = computed({
  set(showPicker) {
    emit("update:show", showPicker);
  },
  get() {
    return props.show;
  },
});
//选项数据
watch(
  () => props.columns,
  (newVal) => {
    state.columns = newVal;
  },
  { immediate: true }
);
watch(
  () => props.modelValue,
  (newVal) => {
    state.selectItem[props.options.value] = newVal;
  },
  { immediate: true }
);
watch(
  () => state.showPicker,
  (newVal) => {
    //隐藏选择框是,清空搜素栏value值
    //1.如果是可搜素的 清空选项
    //2.如果不是可搜素的,把传过来的选项数据,赋值给当前组件选项数据中
    if (!newVal) {
      state.searchVal = "";
      props.remote && (state.columns = []);
    } else {
      !props.remote && (state.columns = props.columns);
    }
  }
);
</script>

<style lang="scss" scoped>
.van-field-box {
  height: 264px;
  overflow-y: auto;
  padding-bottom: 20px;
}
::v-deep(.van-cell) {
  &.selected {
    background: #f5f7fa;
    color: #1989fa;
  }
}
</style>

注意:需要你安装一下lodash-es (因为远程搜索我加了一个防抖处理)
npm install lodash-es

2.父组件使用

<template>
  <div class="sel-picker">
    <van-field v-model="state.selectItem.label" is-link readonly label="城市" placeholder="选择城市" @click="fieldClick" />
    <van-field-select-picker
      v-model="state.selectItem.value"
      v-model:show="state.show"
      placeholder="请选择"
      :columns="state.columns"
      :options="{ label: 'label', value: 'value' }"
      isSearch
      @confirm="confirm"
    ></van-field-select-picker>
  </div>
</template>

<script setup lang="ts">
import vanFieldSelectPicker from "@/components/vanFieldSelectPicker.vue";
import { reactive } from "vue";
let state = reactive({
  show: false,
  selectItem: { label: "", value: "" },
  columns: [
    { label: "北京", value: "beijing" },
    { label: "上海", value: "shanghai" },
    { label: "深圳", value: "shenzhen" },
    { label: "广州", value: "guangzhou" },
    { label: "杭州", value: "hangzhou" },
    { label: "重庆", value: "chongqing" },
  ],
});
const fieldClick = () => {
  state.show = true;
};
const confirm = (item) => {
  console.log(item);
  state.selectItem = item;
};
</script>
<style scoped lang="scss"></style>

下一章封装vue3.x vant 移动端多选的select效果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值