这里写目录标题
- 前言
- 组件
- 选择器视图
- 选择器
- 组件使用示例
 
- 注意事项
- 扩展
前言
基于 Vant的checkbox配合popup和input定制选择器 实现一个React的版本
 组件库:antd mobile
 适用:移动端
 UI如下:
 
 功能点:
- 选择器在弹出层内,取消隐藏,确定带回选项
- 选项展示数据可动态自定义,选项带出数据可动态自定义
- 输入框动态展示
- 输入框分为两个功能:过滤和远程搜索
- 已选项定位到其位置(当选了第三个数据,再打开弹窗时,列表定位到第三个数据)
组件
选择器视图
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 />做成单选+多选



















