IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> React Antd4一个简单FilterForm和一个广告魔方的封装 -> 正文阅读

[JavaScript知识库]React Antd4一个简单FilterForm和一个广告魔方的封装

1、一个列表页面都是查询和列表。查询的功能是比较常用的。对于一个项目来说把这块做成公共的组件更好维护,而且通过注册不同的搜索控件,避免大家重复写相同功能的代码.

支持容器和列自适应布局,支持自定义注册和字段值的收集转换和值有效验证,支持多字段名

2、移动端广告位自定义布局的组件

先看效果:

页面DEMO例子代码:

 addExample("魔方", ['./common.tsx?tsx', 'antd4', 'ant-design-icons', 'ahooks'], function (common, antd, icons, ahooks) {
            addLessText(`
                        .cube-wrapper{
                            position:relative;
                        }
                        .cube-tiles{
                            width:100%;
                            height:100%;
                        }
                        .cube-row{
                            display:flex;
                        }
                        .cube-cell{
                            border-top:solid 1px #d9d9d9;
                            border-left:solid 1px #d9d9d9;
                        } 
                        .cube-row .cube-cell:last-child{
                            border-right:solid 1px #d9d9d9;
                        }  
                        .cube-row:last-child .cube-cell{
                            border-bottom:solid 1px #d9d9d9;
                        }  
                        .cube-cell-hover{
                            background:#e8f7fd
                        }
                        .cube-places{
                            width:100%;
                            height:100%;
                        }
                        .place-item{
                            position:absolute;
                            background:#e8f7fd;
                            border:solid 1px #d9d9d9;
                            box-sizing:initial;
                        }
                        .place-item-selected{
                            border-color:#1890ff;
                            z-index:3;
                        }
                        .place-item-remove{
                            position:absolute;
                            right:-5px;
                            top:-10px;
                            display:none;
                            color:#69c0ff;
                            cursor:pointer;
                        }
                        .place-item-selected  .place-item-remove{
                            display:block;
                        }
                        .tmp-ul{

                        }
                        .tmp-item{
                            border: 1px solid #efefef;
                            padding:5px;
                            float:left;
                            width:80px;
                            height:80px;
                            display:flex;
                            flex-direction: column;
                        }
                        .tmp-item:nth-child(n+2){
                            margin-left:5px;
                        }
                        .tmp-row{
                            display:flex;
                            flex:1;

                        }
                        .tmp-row:nth-child(n+2){
                            margin-top:5px;
                        }
                        .tmp-col{
                            flex:1;
                            height:100%;
                            background-color:#44aadd;
                        }
                        .tmp-col:nth-child(n+2){
                            margin-left:5px;
                        }
                `)
            let { Form, Row, Col, Input, Select, Card } = antd
            let { UploadImage } = common
            let { CloseCircleOutlined, CloseCircleFilled } = icons
            let { useControllableValue } = ahooks
            let { useState, useCallback, useEffect, useMemo } = React

            window.ahooks = ahooks
            let Cube = (props, ref) => {
                let { size, rows, cols, type = "customize" } = props; // type fixed,customize
                let [currentPlaceActiveIndex, setCurrentPlaceActiveIndex] = React.useState(0)
                let [tiles, setTiles] = React.useState([])
                let [places, setPlaces] = useControllableValue(props, {
                    defaultValue: [],
                    defaultValuePropName: 'defaultValue',
                    valuePropName: 'places',
                    trigger: 'onChange',
                })
                let instance = React.useRef({
                    currentTileValue: 0,
                    startTile: null,
                    mounted: false,
                }).current
                let [tileWidth, tileHeight] = React.useMemo(() => {
                    return [size[0] / cols, size[1] / rows]
                }, [size[0], size[1], rows, cols])
                React.useLayoutEffect(() => {
                    let tiles = Array.from(new Array(rows), (v, r) => {
                        return Array.from(new Array(cols), (v, c) => {
                            return {
                                id: 'row_' + r + '_col_' + c,
                                row: r,
                                col: c,
                                value: 0,// 0 空白,大于0表示被占位
                                active: false
                            }
                        })
                    })
                    setTiles(tiles)
                }, [rows, cols])

                let [canHover, setCanHover] = React.useState(false)

                let eachTiles = React.useCallback((callback) => {
                    rowLoop:
                    for (let r = 0, rowLength = tiles.length; r < rowLength; r++) {
                        colLoop:
                        for (let c = 0, colLength = tiles[r].length; c < colLength; c++) {
                            let result = callback(tiles[r][c], r, c)
                            if (result === false) {
                                break rowLoop
                            }
                        }
                    }
                }, [tiles])

                let boxBoxIntersect = React.useCallback((x1, y1, w1, h1, x2, y2, w2, h2) => {
                    // 性能最好的矩形相交判断
                    return !(x1 > x2 + w2 || x1 + w1 < x2 || y1 > y2 + h2 || y1 + h1 < y2)
                }, [])

                let paintTiles = React.useCallback((currentTile) => {
                    let startTile = instance.startTile
                    let minRow = Math.min(startTile.row, currentTile.row)
                    let maxRow = Math.max(startTile.row, currentTile.row)
                    let minCol = Math.min(startTile.col, currentTile.col)
                    let maxCol = Math.max(startTile.col, currentTile.col)
                    if (!places.some(place => {
                        let x1 = place.min[0], y1 = place.min[1], w1 = place.max[0] - place.min[0], h1 = place.max[1] - place.min[1]
                        let x2 = minCol, y2 = minRow, w2 = maxCol - minCol, h2 = maxRow - minRow
                        let result = boxBoxIntersect(x1, y1, w1, h1, x2, y2, w2, h2)
                        return result
                    })) {
                        eachTiles(tile => {
                            let x1 = tile.col, y1 = tile.row, w1 = 0, h1 = 0
                            let x2 = minCol, y2 = minRow, w2 = maxCol - minCol, h2 = maxRow - minRow
                            let result = boxBoxIntersect(x1, y1, w1, h1, x2, y2, w2, h2)
                            if (result) {
                                tile.active = true
                            } else {
                                tile.active = false
                            }
                        })
                        setTiles([...tiles])
                    }
                }, [places, tiles, eachTiles])
                   

                let eachTilesRange = React.useCallback((startCol, startRow, endCol, endRow, callback) => {
                    let minRow = Math.min(startRow, endRow)
                    let maxRow = Math.max(startRow, endRow)
                    let minCol = Math.min(startCol, endCol)
                    let maxCol = Math.max(startCol, endCol)
                    // 检查当前区域是否存在占位
                    eachTiles((tile, row) => {
                        if (tile.row >= minRow && tile.row <= maxRow && tile.col >= minCol && tile.col <= maxCol) {
                            callback(tile)
                        }
                    })
                }, [eachTiles])


                let onMouseDown = React.useCallback((tile, e) => {
                    if (tile.value > 0) {
                        return
                    }
                    if (!instance.startTile) {
                        instance.startTile = tile
                        tile.active = true;
                        setTiles([...tiles])
                        return
                    }
                    // 结束
                    if (instance.startTile) {
                        instance.startTile = null
                        //   instance.currentTileValue++
                        let minTile, maxTile;
                        eachTiles((tile) => {
                            if (tile.active && tile.value === 0) {
                                tile.active = false
                                tile.value = 1
                                if (!minTile) {
                                    minTile = tile
                                }
                                if (!maxTile) {
                                    maxTile = tile
                                }
                                if (minTile.row > tile.row || minTile.col > tile.col) {
                                    minTile = tile
                                }
                                if (maxTile.row < tile.row || maxTile.col < tile.col) {
                                    maxTile = tile
                                }
                            }
                        })
                        let newPlaces = [...places]
                        newPlaces.push({
                            value: instance.currentTileValue,
                            min: [minTile.col, minTile.row],
                            max: [maxTile.col, maxTile.row]
                        })
                        setPlaces(newPlaces)
                        setTiles([...tiles])
                    }
                }, [tiles, places, eachTiles])

                let onMouseEnter = React.useCallback((tile, e) => {
                    if (instance.startTile) {
                        paintTiles(tile)
                    }
                }, [paintTiles])

                let onSelectPalceHandle = React.useCallback((place, index) => {
                    setCurrentPlaceActiveIndex(index)
                }, [])

                let placeNodes = React.useMemo(() => {
                    return places.map(place => {
                        let min = place.min
                        let max = place.max
                        let left = min[0] * tileWidth, top = min[1] * tileHeight;
                        let width = (max[0] - min[0] + 1) * tileWidth, height = (max[1] - min[1] + 1) * tileHeight
                        return {
                            value: place.value,
                            min: min,
                            max: max,
                            style: {
                                left: left,
                                top: top,
                                width: width,
                                height: height
                            }
                        }
                    })
                }, [places, tileWidth, tileHeight])

                let renderTiles = React.useCallback(() => {
                    return <div className="cube-tiles">{tiles.map((row, r) => {
                        return <div key={r} className="cube-row">
                            {row.map((tile, c) => {
                                let cls = classNames('cube-cell', {
                                    'cube-cell-hover': tile.active
                                })
                                return <div onMouseDown={onMouseDown.bind(null, tile)} onMouseEnter={onMouseEnter.bind(null, tile)} className={cls} key={tile.id} style={{
                                    width: tileWidth,
                                    height: tileHeight
                                }}></div>
                            })}
                        </div>
                    })}</div>
                }, [tiles, tileWidth, tileHeight])
                let renderPlaces = React.useCallback(() => {
                    return <div className="cube-places">{
                        placeNodes.map((place, index) => {
                            let cls = classNames('place-item', {
                                'place-item-selected': currentPlaceActiveIndex === index
                            })
                            return <div onClick={onSelectPalceHandle.bind(null, place, index)} key={index} className={cls} style={place.style}>
                                {type === 'customize' ? <span className="place-item-remove" onClick={(e) => {
                                    e.stopPropagation()
                                    places.splice(index, 1)
                                    eachTilesRange(place.min[0], place.min[1], place.max[0], place.max[1], (d => {
                                        if (d.value > 0) {
                                            d.value = 0
                                        }
                                    }))
                                    setTiles([...tiles])
                                    setPlaces([...places])

                                }}><CloseCircleFilled /></span> : null}
                            </div>
                        })
                    }</div>
                }, [placeNodes, eachTiles, currentPlaceActiveIndex, type])

                React.useLayoutEffect(() => {
                    if (instance.mounted) {

                    } else {
                        instance.mounted = true
                    }
                }, [rows, cols])

                return <div className="cube-wrapper" style={{ width: size[0], height: size[1] }}>
                    {renderTiles()}
                    {renderPlaces()}
                </div>
            }
            Cube = React.forwardRef(Cube)
            let CubeTemplate = (props) => {
                let { data, onSelect } = props

                let onSelectTemplate = useCallback((item) => {
                    if (onSelect) {
                        onSelect(item)
                    }
                }, [onSelect])
                let renderRowCol = (d) => {
                    return Array.from(new Array(d.rows), (row, rowIndex) => {
                        return <div key={rowIndex} className="tmp-row">
                            {Array.from(new Array(d.cols), (col, colIndex) => {
                                return <div key={colIndex} className="tmp-col"></div>
                            })}
                        </div>
                    })
                }
                return <ul className="tmp-ul">
                    {data.map((d, index) => {
                        return <li key={index} className="tmp-item" onClick={onSelectTemplate.bind(null, d)}>
                            {renderRowCol(d)}
                        </li>
                    })}
                </ul>

            }
            return function (props) {
                let { children, ...restProps } = props
                let [places, setPlaces] = useState([])
                let [{ rows, cols }, setGridRowCol] = React.useState({
                    rows: 4,
                    cols: 4,
                })
                let grids = React.useMemo(() => [[4, 4], [5, 5], [6, 6]].map((d, i) => {
                    return {
                        rows: d[0],
                        cols: d[1],
                        value: d.join('x'),
                    }
                }), [])
                let tempaltes = React.useMemo(() => {
                    return [{
                        rows: 1,
                        cols: 2,
                        text: "1行2列",
                        places: [{
                            min: [0, 0],
                            max: [0, 0]
                        }, {
                            min: [1, 0],
                            max: [1, 0]
                        }]
                    }, {
                        rows: 1,
                        cols: 3,
                        text: "1行3列",
                        places: [{
                            min: [0, 0],
                            max: [0, 0]
                        }, {
                            min: [1, 0],
                            max: [1, 0]
                        }, {
                            min: [2, 0],
                            max: [2, 0]
                        }]
                    }, {
                        rows: 1,
                        cols: 4,
                        text: "1行4列",
                        places: [{
                            min: [0, 0],
                            max: [0, 0]
                        }, {
                            min: [1, 0],
                            max: [1, 0]
                        }, {
                            min: [2, 0],
                            max: [2, 0]
                        }, {
                            min: [3, 0],
                            max: [3, 0]
                        }]
                    }, {
                        rows: 2,
                        cols: 2,
                        text: "2行2列",
                        places: [{
                            min: [0, 0],
                            max: [0, 0]
                        }, {
                            min: [1, 0],
                            max: [1, 0]
                        }, {
                            min: [0, 1],
                            max: [0, 1]
                        }, {
                            min: [1, 1],
                            max: [1, 1]
                        }]
                    }]
                }, [])
                let onSelectTempalte = useCallback((temp) => {
                    setGridRowCol({
                        rows: temp.rows,
                        cols: temp.cols
                    })
                    setPlaces(temp.places)
                }, [])
                let onPlaceChange = useCallback((places) => {
                    setPlaces(places)
                }, [])
                return <Card>
                    <Form wrapperCol={{ span: 18 }} labelCol={{ span: 6 }}>
                        <Form.Item label="方案名称">
                            <Input />
                        </Form.Item>
                        <Form.Item label="选择模板">
                            <CubeTemplate onSelect={onSelectTempalte} data={tempaltes}></CubeTemplate>
                        </Form.Item>
                        <Form.Item label="魔方密度">
                            <Select onChange={(value) => {
                                setGridRowCol({
                                    rows: parseInt(value.split('x')[0]),
                                    cols: parseInt(value.split('x')[1])
                                })
                            }}>
                                {grids.map((d, i) => <Select.Option key={d.value} value={d.value}>{d.value}</Select.Option>)}
                            </Select>
                        </Form.Item>
                        <Form.Item label="布局">
                            <Cube places={places} onChange={onPlaceChange} size={[375, 375]} rows={rows} cols={cols}></Cube>
                        </Form.Item>
                    </Form>
                </Card>
            }
        })  

addExample("标准列表", ['antd4', './common.tsx?tsx'], function (antd, common) {
            let { useRequest, useModal, ORDER, ImageView, DTable, FilterForm, useTableSelection } = common
            let { Tabs, Table, Button, Card, Space, message, Modal, Descriptions, Typography, Pagination, Badge, Tooltip, Image } = antd
            let { useState, useCallback, useMemo, useRef, useEffect, forwardRef } = React
            let ImageGroupPreview = (props) => {
                let { images, visible, onVisibleChange, privewProps } = props
                return <div style={{ display: 'none' }}>
                    <Image.PreviewGroup preview={{
                        ...(privewProps || {}), visible: visible, onVisibleChange: (visible, preVisible) => {
                            if (onVisibleChange) {
                                onVisibleChange(visible, preVisible)
                            }
                        }
                    }}>
                        {images.map((src, index) => <Image key={index + src} src={src} />)}
                    </Image.PreviewGroup>
                </div>
            }
            let List = () => {
                let [{ tableProps, dataSource, update }, { query: showList }] = useRequest({
                    service: () => Promise.resolve({
                        list: [{
                            id: 1,
                            buyerName: "鲜花",
                            score: 4,
                            scoreTaste: 4,
                            scorePack: 3,
                            scoreFlow: 3,
                            content: Mock.Random.cword(100),
                            reviewPicUrl: [Mock.Random.image('300x300', '#ff0000'), Mock.Random.image('300x300', '#00ff00'), Mock.Random.image('300x300', '#0000ff')].join(','),
                            status: 1,
                            createdTime: "2021-09-14 11:00:00"

                        }, {
                            id: 2,
                            buyerName: "鲜花",
                            score: 4,
                            scoreTaste: 4,
                            scorePack: 3,
                            scoreFlow: 3,
                            content: Mock.Random.cword(100),
                            reviewPicUrl: '',
                            status: 1,
                            createdTime: "2021-09-14 11:00:00"

                        }],
                        total: 0
                    }),
                    transform: (d) => {
                        return {
                            data: d.list,
                            total: d.total
                        }
                    }
                })
                let [{ rowSelection }, { clearAllSelection }] = useTableSelection({ keep: true })
                let [{ visible: visibleImage, images }, setVisibleImage] = useState({ visible: false, images: [] })
                let viewImages = useCallback((images) => {
                    setVisibleImage({ images: images, visible: true })
                }, [])
                let updateStatusHandle = useCallback((status, ids, isBatch = false) => {

                }, [])
                const fields = useMemo(() => [[{
                    type: "text",
                    name: "name_list",
                    label: "名称"
                }, {
                    type: "select",
                    name: "name_list2",
                    label: "编码",
                    data: [{ text: "禁用", value: 1 }, { text: "启用", value: 2 }]
                }], {
                    type: "text",
                    name: "name2",
                    label: "名工地"
                }, {
                    type: "text",
                    name: "name3",
                    label: "名称城工地"
                }, {
                    type: "text",
                    name: "name4",
                    label: "名称发大水城"
                }, {
                    type: "text",
                    name: "name5",
                    label: "名称大水城"
                }], [])
                const columns = useMemo(() => [
                    {
                        title: '用户昵称',
                        dataIndex: 'buyerName',
                        ellipsis: {
                            showTitle: false,
                        },
                        render: buyerName => (
                            <Tooltip placement="topLeft" title={buyerName}>
                                {buyerName}
                            </Tooltip>
                        ),
                    },
                    {
                        title: '评分',
                        width: 240,
                        render(record) {
                            return (
                                <>
                                    <div>
                                        <Space>
                                            <span>综合评分{record.score}星</span>
                                            <span>口味评分{record.scoreTaste}星</span>
                                        </Space>
                                    </div>
                                    <div>
                                        <Space>
                                            <span>包装评分{record.scorePack}星</span>
                                            <span>物流评分{record.scoreFlow}星</span>
                                        </Space>
                                    </div>
                                </>
                            );
                        },
                    },
                    {
                        title: '文字评价',
                        dataIndex: 'content',
                        // ellipsis:{showTitle:true}
                        responsive: ['md'],//小于 768 不显示
                        render(content) {
                            // return <Typography.Paragraph ellipsis={{
                            //     rows: 3,
                            //     expandable: true,
                            // }}>{content}</Typography.Paragraph>
                            // return <Typography.Paragraph ellipsis={{
                            //     rows: 3,
                            //     expandable: true,
                            //     symbol:"展示"
                            // }}>{content}</Typography.Paragraph>
                            return <Tooltip title={content}>
                                <Typography.Paragraph ellipsis={{
                                    rows: 3,
                                    expandable: false
                                }}>{content}</Typography.Paragraph>
                            </Tooltip>
                        },
                    },
                    {
                        title: '图片评价',
                        dataIndex: 'reviewPicUrl',
                        width: 120,
                        render(reviewPicUrl) {
                            let images = reviewPicUrl.split(',').filter(Boolean)
                            return <Button type="link" onClick={viewImages.bind(null, images)}>查看图片({images.length})</Button>;
                        },
                    },
                    {
                        title: '状态',
                        width: 100,
                        render(record) {
                            let color = record.status == 1 ? 'green' : 'red';
                            let text = record.status == 1 ? '展示中' : '已隐藏';
                            return <Badge text={text} color={color}></Badge>;
                        },
                    },
                    {
                        title: '评价时间',
                        dataIndex: 'createdTime',
                        width: 180
                    },
                    {
                        title: '操作',
                        width: 80,
                        render: (record) => {
                            let status = record.status == 1 ? 0 : 1;
                            return (
                                <Space>
                                    <Button
                                        style={{ padding: 0 }}
                                        type="link"
                                        onClick={() => {
                                            updateStatusHandle(status, [record.id]);
                                        }}
                                    >
                                        {status == 0 ? '隐藏' : '显示'}
                                    </Button>
                                </Space>
                            );
                        },
                    },
                ], [viewImages, updateStatusHandle])

                let viewImageElement = <div style={{ display: 'none' }}>
                    <Image.PreviewGroup preview={{
                        visible: visibleImage, onVisibleChange: vis => {
                            if (!vis) {
                                setVisibleImage({ images: [], visible: vis })
                            }
                        }
                    }}>
                        {images.map((src, index) => <Image key={index} src={src} />)}
                    </Image.PreviewGroup>
                </div>
                return <Card>
                    <FilterForm fields={fields} autoBind onQuery={showList} ></FilterForm>
                    <Table {...tableProps} rowKey="id" columns={columns} rowSelection={rowSelection}></Table>

                    <ImageGroupPreview images={images} visible={visibleImage} onVisibleChange={(vis) => {
                        if (!vis) {
                            setVisibleImage({ images: [], visible: vis })
                        }
                    }}></ImageGroupPreview>
                </Card>
            }
            return function (props) {
                let { children, ...restProps } = props
                return <List></List>
            }
        })

组件代码:



type FilterFormFieldOptions = {
    [key: string]: any
    type?: String
    name: string | string[], // name 是fieldName的便捷写法
    label: string
    key?: string // 唯一key,不设默认为name或index 
    props: any
    fields?:Array<Pick<FilterFormFieldOptions,'fields'>>
    initialValue?: any
    itemProps?: any
    layoutProps?:any
    noLabel?: boolean // 是否显示babel
    noName?: boolean // 是否绑定字段名
    render?: (field: FilterFormFieldOptions) => any,// 返回输入渲染控件
    valid: (value) => boolean // 值是否有效,无效的话,不会附加到查询结果

}
interface FilterFormProps {
    fields: Array<FilterFormFieldOptions>
    onQuery: (queryParams: any) => void,
    autoBind?: boolean
    containerProps?: any
    fieldLayoutProps?: any
    searchLayoutProps?:any
    filterComponents?: any
}

let FilterFormField = (props) => {
    let { field, noLabel = false,children } = props
    children =  field.render?field.render(field, noLabel):children
    let formItemProps = {
        ...(field.itemProps||{})
    }
    noLabel = field.noLabel || noLabel
    if (noLabel !== true) {
        formItemProps.label = field.label
    }
    if (field.noName !== true) {
        formItemProps.name = field.name
    }
    if (field.noName !== true && field.initialValue !== void 0) {
        formItemProps.initialValue = field.initialValue
    }
    return <Form.Item {...formItemProps}>
        {children}
    </Form.Item>
}
let FilterFormArrayField = (props) => {
    let { fields } = props
    let [activeField, setActiveField] = useState(() => fields[0])
    const menu = (
        <Menu>
            {fields.map(field => <Menu.Item key={field.key} onClick={() => {
                setActiveField(field)
            }}>{field.label}</Menu.Item>)}
        </Menu>
    );
    return <Form.Item label={<Dropdown overlay={menu} trigger="click"><div>{activeField.label}<DownOutlined /></div></Dropdown>}>
        <FilterFormField field={activeField} noLabel={true}></FilterFormField>
    </Form.Item>
}
const FilterFormContext = React.createContext()

export let FilterForm: FC<FilterFormProps> = forwardRef((props, ref) => {
    let { fields, onQuery, autoBind = false, filterComponents,searchLayoutProps, fieldLayoutProps, containerProps, ...formProps } = props
    let [firstBreakpoint,activeBreakpoints]=useActiveBreakpoint()
    let [form]=Form.useForm()
    //normalization Normalize standard
    let normalizeFields = useCallback((fields, callback) => {
        return fields.map((field, index) => {
            if(Array.isArray(field)){
                field={
                    fields:field
                }
            }
            let baseField = filterComponents[field.type] || {}
            let newField = _.assignWith({
                key: field.key || (Array.isArray(field.name) ? field.name.join('_$_') : field.name) || index,
                props: {},
                //itemProps: {},
                //layoutProps:{},
                noLabel: false,
                noName: false
            }, baseField, field, (objValue, srcValue, key, obj, source) => {
                if (_.isPlainObject(srcValue)) {
                    return _.assign(objValue, srcValue)
                }
            })
            if (newField.fields&&Array.isArray(newField.fields)) {
                newField.fields=normalizeFields(newField.fields, callback)
                newField.key=newField.fields.map(d=>d.key).join('_')
                newField.isMultField=true;
         
            }else{
                callback&&callback(newField)
            }
            return newField
        })
    }, [filterComponents])
    let [mergeFields, fieldMap] = useMemo(() => {
        let fieldMap = new Map()
        let newFields = normalizeFields(fields, (field) => {
            if (Array.isArray(field.name)) {
                field.name.forEach((cname) => {
                    fieldMap.set(cname, field)
                })
            } else {
                fieldMap.set(field.name, field)
            }
        })
        return [newFields, fieldMap]
    }, [fields, normalizeFields])
    let getFieldColSpan=useCallback((field)=>{
        let layoutProps=field.layoutProps||fieldLayoutProps
        let span=layoutProps.span
        let breakpoint=activeBreakpoints.find(breakpoint=>layoutProps[breakpoint])
        if(breakpoint){
            span=layoutProps[breakpoint].span
        }
        return span
    },[activeBreakpoints,fieldLayoutProps])

    let renderField = (field, index) => {
        let layoutProps=field.layoutProps||fieldLayoutProps
        return <Col {...layoutProps} key={field.key}>
            { field.isMultField ? <FilterFormArrayField fields={field.fields} ></FilterFormArrayField> : <FilterFormField field={field}></FilterFormField>}
        </Col>
    }
    let onFinishHandle = useCallback((values) => {
        let fieldKeys = Object.keys(values)
        let queryParams = {}
        fieldKeys.forEach((fieldName) => {
            let value = values[fieldName]
            let field = fieldMap.get(fieldName)
            if (!field) {
                return
            }
            let isValidValue = true
            if(field.valid){
                isValidValue=field.valid(value, fieldName, field)
            }else{
                isValidValue=value!==undefined
            }

            // 如果值有效,就设置
            if (isValidValue) {
                queryParams[fieldName] = value
            }
        })
        if (onQuery) {
            console.log('queryParams',queryParams)
            onQuery(queryParams)
        }
    }, [onQuery, fieldMap])
    let onQueryHandle=useCallback(()=>{
        form.validateFields().then(onFinishHandle).catch(()=>{

        })
    },[form,onFinishHandle])
    let onResetHandle=useCallback(()=>{
        form.resetFields()
    },[form])
    mergeFields=useMemo(()=>{
        let menu=(<Menu>
            <Menu.Item key="reset" onClick={onResetHandle}>重置</Menu.Item>
        </Menu>)
        let layoutProps=searchLayoutProps||fieldLayoutProps
         let searchField={
             type:"search",
             key:"__search__",
             noName:true,
             label:<div></div>,
             itemProps:{
                 colon:false,
             },
             layoutProps:layoutProps,
             props:{
                 overlay:menu,
                 trigger:"click",
                 type:"primary",
                 onClick:onQueryHandle,
                 children:'搜索'
             },
             render(field){
                 return <Dropdown.Button {...field.props}></Dropdown.Button>
             }
         }
         let allFieldTotalSpan=mergeFields.reduce((a,b)=>a+getFieldColSpan(b),0)
         let currentSpan=getFieldColSpan(searchField)
         let p=allFieldTotalSpan%24
         if(p>0&&currentSpan+p<=24){
            searchField.label=null
            searchField.props.style={
                marginLeft:20
            }
         }
         return mergeFields.concat(normalizeFields([searchField]))
    },[getFieldColSpan,searchLayoutProps,fieldLayoutProps,onQueryHandle,onResetHandle])
    useEffect(()=>{
        if(autoBind){
            onQueryHandle()
        }
    },[])
    return <Row>
        <Col {...containerProps}>
            <Form component={false} colon={false} {...formProps} form={form} onFinish={onFinishHandle}>
                <Row>
                    {mergeFields.map(renderField)}
                </Row>
            </Form>
        </Col>
    </Row>
})
FilterForm.fieldComponents = {}
FilterForm.registerField = function (type: string, config: FilterFormFieldOptions) {
    FilterForm.fieldComponents[type] = {
        ...config
    }
}
FilterForm.defaultProps = {
    filterComponents: FilterForm.fieldComponents,
    wrapperCol: {
        flex: 1
    },
    labelCol: {
        flex: '0 1 120px'
    },
    containerProps: {
        span: 24
    },
    fieldLayoutProps: {
        span: 8
    }
}
FilterForm.registerField('text', {
    render(field) {
        return <Input {...field.props}></Input>
    }
})
FilterForm.registerField('select', {
    render(field) {
        let children = field.data ? field.data.map(d => <Select.Option key={d.value} value={d.value}>{d.text}</Select.Option>) : null
        return <Select {...field.props}>{children}</Select>
    }
})

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2021-09-22 14:35:15  更:2021-09-22 14:37:39 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/18 22:48:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码