【React】实现输入框切换

需求

类似designable-antd平台的这个切换功能:

  • 点击右边按钮,可以切换不同的输入框样式。

实现

  • 维护一个type-component的类型数组
  • 遍历数组,找到当前组件类型并渲染
  • 当切换输入框样式的时候,获取下一个组件类型并渲染。如果为最后一个组件,则重新循环为第一个组件类型并展示
  • 初始化的时候,需要根据value校验当前组件的类型,并渲染

polyInput.tsx:

javascript 复制代码
import React, { useEffect, useState, useMemo } from 'react';
import { Button, Row, Tooltip } from 'antd';
import { useField } from '@formily/react';
import { Field } from '@formily/core';

export interface IInput {
  value: any;
  onChange: (value: any) => void;
}

export interface IPolyType {
  type: string;
  icon: JSX.Element;
  component?: any;
  checker: (value: any) => boolean;
}

export type PolyTypes = IPolyType[];

export function createPolyInput(polyTypes: PolyTypes = []): React.FC<IInput> {
  return ({ value, ...props }) => {
    const [curType, setCurType] = useState(polyTypes[0]?.type);

    const field: Field = useField();

    const curTypeItem = polyTypes.filter((i) => i.type === curType)[0];

    useEffect(() => {
      // 设置默认类型
      polyTypes?.forEach(({ checker, type }) => {
        if (checker(value)) { // here
          setCurType(type);
        }
      });
    }, []);

    const getNextType = () => {
      const currentIndex = polyTypes?.findIndex(({ type }) => type === curType);
      const nextIndex = currentIndex + 1 > polyTypes?.length - 1 ? 0 : currentIndex + 1;
      return polyTypes[nextIndex];
    };

    const renderContent = useMemo(() => {
      return (
        <>
          {curTypeItem?.component && (
            <div style={{ flex: 1, marginRight: 5 }}>
              {/* @ts-ignore */}
              {React.createElement(curTypeItem?.component, {
                ...props, // here
                value,
              })}
            </div>
          )}
          <Tooltip title={curTypeItem.type}>
            <Button
              icon={curTypeItem.icon}
              onClick={() => {
                const nextType = getNextType(); // here
                if (nextType.type === curType) {
                  return;
                }
                setCurType(nextType?.type);
                field?.setValue(undefined); // 切换类型的时候,赋空值
              }}
            />
          </Tooltip>
        </>
      );
    }, [curTypeItem]);

    return <Row justify="start">{renderContent}</Row>;
  };
}

使用:

javascript 复制代码
import { FieldStringOutlined, SwitcherOutlined } from '@ant-design/icons';
import { isObject } from 'lodash';
import { Switch } from '@formily/antd';
import LanguageTextRule, { LanguageComponentType } from '../LanguageTextRule';
import { createPolyInput } from '../PolyInput';

export enum ValidatorType {
  BOOLEAN = 'boolean',
  LANGUAGE_MESSAGE = 'message',
}

export const isBoolean = (value: any) => typeof value === 'boolean';
export const isObj = (value: any) => isObject(value);

export const ValidatorTypesMap = [
  {
    type: ValidatorType.BOOLEAN,
    icon: <SwitcherOutlined />,
    component: Switch,
    checker: isBoolean,
  },
  {
    type: ValidatorType.LANGUAGE_MESSAGE,
    icon: <FieldStringOutlined />,
    component: (props: any) => {
      return (
        <LanguageTextRule
          title="Error Message"
          componentType={LanguageComponentType.TEXT}
          buttonText="+ Error Message"
          isModal
          {...props}
        />
      );
    },
    checker: isObj,
  },
];

export default createPolyInput(ValidatorTypesMap);

效果

相关推荐
Moment2 小时前
Cursor 2.0 支持模型并发,我用国产 RWKV 模型实现了一模一样的效果 🤩🤩🤩
前端·后端·openai
狂炫冰美式2 小时前
QuizPort 1.0 · 让每篇好文都有测验陪跑
前端·后端·面试
咋吃都不胖lyh2 小时前
.docx 和 .doc 是 Microsoft Word 文档的两种主要文件格式
前端·html·xhtml
哈乐2 小时前
网工应用题:配置命令补全类题目
服务器·前端·网络
uuai2 小时前
echarts不同版本显示不一致问题
前端·javascript·echarts
自然 醒2 小时前
企业微信自建应用开发详细教程,如何获取授权链接?如何使用js-sdk?
javascript·vue.js·企业微信
AKclown3 小时前
基于Monaco的diffEditor实现内容对比
前端·vue.js·react.js
Moonbit3 小时前
MoonBit Pearls Vol.12:初探 MoonBit 中的 Javascript 交互
javascript·后端·面试
chenbin___3 小时前
react native中 createAsyncThunk 的详细说明,及用法示例(转自通义千问)
javascript·react native·react.js
摆烂工程师3 小时前
(2025年11月)开发了 ChatGPT 导出聊天记录的插件,ChatGPT Free、Plus、Business、Team 等用户都可用
前端·后端·程序员