vue3+vant4 singlePicker单选组件(picker+popup)

1,658 阅读1分钟

vue2过渡vue3,挺多的写法都不一样,所以记录一下用vue3 setup语法糖二次封装vant组件并使用,其实写多几个基本上就将vue经常所用到的watch,prop,emit,生命周期,定义响应式变量等,这些到时候另外再细写,这里主要给到代码方便使用。

vantUI框架不像elementUIPC端框架的select可以直接使用,大多数都需要结合二次封装,下面想实现类似下图的单选组件

image.png

子组件 singlePicker.vue

下面的代码其实不难,这里主要说一下有一个prop属性是customFieldName,这个主要考虑到传入的option数据的不同来处理了的,例如现在默认是text和value,但如果传入的数据内容不是按照text,value,就可以用customFieldName来改变。举个例子:如果传入的columns是[{name:'是',code:'1'},{name:'否',code:'0'},{name:'未知',code:'2'},] ,那么使用该组件的时候就传入 :customFieldName="{text:'name',value:'code'}"即可。下面是子组件的代码:

<template>
    <div>
        <van-field v-model="text" v-bind="$attrs" readonly is-link :name="name" :label="label" @click="show = !show"></van-field>
        <van-popup :show="show" round position="bottom">
            <van-picker
            :columns="columns"
            :columns-field-names="customFieldName"
            show-toolbar
            :value-key="valueKey"
            :title="$attrs.label"
            @cancel="show = !show"
            @confirm="onConfirm"
            ></van-picker>
        </van-popup>
    </div>
</template>

<script setup>
import { ref,toRefs, defineProps,onMounted,watch,reactive,nextTick,defineEmits } from 'vue';
const emit = defineEmits(['update:modelValue'])
const props = defineProps({
//子组件接收父组件传递过来的值
    columns: {
        type:Array // option中的数据
    },
    label:String, // 标题
    modelValue:String, // 绑定的值
    customFieldName:{  // option中数据中对应的name和code的字段名
        type:Object,
        default:{
            text: 'text',
            value: 'value',
        }
    },
    name:String,
})
//使用父组件传递过来的值
const {info} = toRefs(props)

onMounted(()=>{
    nextTick(()=>{
        reShow();
    })
})

let show = ref(false)
let text = ref('')
let code = ref('')
const onConfirm = ({ selectedOptions }) => {
    // text.value = selectedOptions[0].text;
    // code.value = selectedOptions[0].value;
    text.value = selectedOptions[0][props.customFieldName.text];
    code.value = selectedOptions[0][props.customFieldName.value];
    show.value = !show.value;
}

const reShow = () => {
    if(props.modelValue) {
        props.columns.forEach(res => {
            if (res[props.customFieldName.value] == props.modelValue) {
                text.value = res[props.customFieldName.text];
            }
        })
    }
}

watch(()=>code.value,(newVal, oldVal) => {
    emit('update:modelValue', newVal);
})

watch(()=>props.columns,(newVal,oldVal)=>{
    //处理异步数据回显
    reShow();
})

watch(()=>props.modelValue,(newVal,oldVal)=>{
    //处理异步数据回显
    reShow();
})

</script>

使用子组件 index.vue

<single-picker clearable label="地点" name="role" placeholder="请选择地点" 
    v-model="form.role" v-bind:columns="itemList" 
    :rules="[{ required: true, message: '请选择地点' }]"/>
<script setup>
import { reactive } from 'vue';
    const itemList = reactive([
        { text: '杭州', value: 'Hangzhou' },
        { text: '宁波', value: 'Ningbo' },
        { text: '温州', value: 'Wenzhou' },
        { text: '绍兴', value: 'Shaoxing' },
        { text: '湖州', value: 'Huzhou' },
    ])

    const form = reactive({role: ""})
</script>

参考博文:# vue3 vant picker封装select 并支持回显清空