【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);

效果

相关推荐
waylon111131 分钟前
【HOC】高阶组件在Vue老项目中的实战应用 - 模块任意排序
前端·vue.js·面试
阳阳羊2 分钟前
Mpx 动画
前端
编程社区管理员3 分钟前
「2025最新版React+Ant Design+Router+TailwindCss全栈攻略:从零到实战,打造高颜值企业级应用
前端·react.js·前端框架
DJA_CR3 分钟前
解决在 TSX 中使用 `RouterView` + `KeepAlive` 不生效问题
前端·vue.js
前端爆冲13 分钟前
项目中无用export的检测方案
前端
旧味清欢|24 分钟前
关注分离(Separation of Concerns)在前端开发中的实践演进:从 XMLHttpRequest 到 Fetch API
javascript·http·es6
热爱编程的小曾41 分钟前
sqli-labs靶场 less 8
前端·数据库·less
gongzemin1 小时前
React 和 Vue3 在事件传递的区别
前端·vue.js·react.js
Apifox1 小时前
如何在 Apifox 中通过 Runner 运行包含云端数据库连接配置的测试场景
前端·后端·ci/cd
-代号95271 小时前
【JavaScript】十四、轮播图
javascript·css·css3