使用antd mobile的PickerView二次封装成业务所需选择器

前言

基于 Vant的checkbox配合popup和input定制选择器 实现一个React的版本
组件库:antd mobile
适用:移动端
UI如下
在这里插入图片描述
功能点

  1. 选择器在弹出层内,取消隐藏,确定带回选项
  2. 选项展示数据可动态自定义,选项带出数据可动态自定义
  3. 输入框动态展示
  4. 输入框分为两个功能:过滤和远程搜索
  5. 已选项定位到其位置(当选了第三个数据,再打开弹窗时,列表定位到第三个数据)

组件

选择器视图

import {PickerView} from "antd-mobile";
import React from "react";

const Select = (props) => {
    const {showOptions, value, setValue} = props;
    return <PickerView
        columns={showOptions}
        value={value}
        onChange={val => {
            setValue(val)
        }}
    />
}
Select.propTypes = {
    showOptions: propTypes.array, //选择器列表数据
    value: propTypes.oneOfType([
        propTypes.string,
        propTypes.number,
        propTypes.object, //指定为多种类型的一种
    ]),
    setValue: propTypes.func,
};
Select.defaultProps = {
    showOptions: [],
};

export default React.memo(Select);

选择器

import React, {memo, useCallback, useEffect, useMemo, useState} from "react";
import {Button, SearchBar, PickerView, Popup} from "antd-mobile";
import propTypes from "prop-types";
import "./index.scss";
import Select from "./select";


function Filter(props) {
    const {
        placeholder,
        filterable,
        remote,
        defaultValue,
        showPicker = true,
        setShowPicker,
    } = props;
    const [searchText, setSearchText] = useState("");
    const [value, setValue] = useState([]);

    useEffect(() => {
        setValue([defaultValue]);
    }, [defaultValue]);
    /**
     * 根据是否可过滤来获取下拉列表
     * 依据为输入框是否有值
     * 由于showOptions要求是二维数组,所以返回值包了一层
     */
    const showOptions = useMemo(() => {
        if (!searchText) {
            return [props.children.slice(0)];
        } else if (filterable && !remote) {
            return [props.children.filter((item) => item.label.indexOf(searchText) > -1)] || []
        }
    }, [props.children, searchText])
    /**
     * 当输入框值发生改变时,判断是远程搜索,还是内部过滤
     */
    const searchValue = (val) => {
        setSearchText(val)
        if (remote) {
            props.search(val);
        }
    };
    /**
     * 提交值:选了数据才触发事件,否则仅关闭弹出层
     */
    const onConfirm = () => {
        if (value) {
            props.confirm(value[0]); //由于value是数组,所以默认取索引0的值
            setSearchText("");
        }
        setShowPicker(false);
    };
    return (
        <>
            <Popup
                visible={showPicker}
                position="bottom"
                bodyStyle={{width: "100vw", height: "50vw"}}
            >
                <div className="flex-side">
                    <Button
                        color="primary"
                        fill="none"
                        onClick={() => setShowPicker(false)}
                        style={{
                            '--text-color': '#969799'
                        }}
                    >
                        取消
                    </Button>
                    <Button color="primary" fill="none" onClick={() => onConfirm()}
                            style={{
                                '--text-color': '#969799'
                            }}>
                        确定
                    </Button>
                </div>
                {(remote || filterable) && (
                    <SearchBar
                        placeholder={placeholder}
                        value={searchText}
                        onChange={(val) => searchValue(val)}
                        className="filter-input"
                        clearable
                    />
                )}
                <Select
                    showOptions={showOptions}
                    setValue={setValue}
                    value={value}
                ></Select>
            </Popup>
        </>
    );
}

Filter.propTypes = {
     filterable: propTypes.bool,//数据过滤标识
    remote: propTypes.bool, //远程搜索标识,默认为false
    search: propTypes.func, //远程搜索事件函数
    showPicker: propTypes.bool, //弹窗展示
    defaultValue: propTypes.oneOfType([ //默认选项
        propTypes.string,
        propTypes.number,
        propTypes.object, //指定为多种类型的一种
    ])
};
Filter.defaultProps = {
    filterable: false,
    remote: false,
    showPicker: true,
    defaultValue: null
};
export default React.memo(Filter);

组件使用示例

<div className="comment-eml-info" onClick={() => openPicker()}></div>
{showPicker &&
            <Filter setShowPicker={setShowPicker} placeholder={'请输入'} filterable={true} defaultValue={defaultValue}
                    label="name" search-value="item" confirm={confirm}>
                {
                    recipients.map(item => ({
                        ...item,
                        label: item.name,
                        value: item
                    }))
                }
            </Filter>}



const openPicker = () => {
    setShowPicker(true);
};
const confirm= (item) => {
    setDefaultValue(item)
    setShowPicker(false)
    arr.push(item);
    setData(arr);
};

注意事项

pickerView组件绑定的columns是二维数组,value是一维数组,在做数据时需小心数据类型
当value值传的是对象时,组件底层会由于key值报错,这个还没解决

扩展

这里的pickerView只能做单选,可以使用<CheckList />做成单选+多选
代码指路: my Demo

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值