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

效果

相关推荐
大黄说说17 分钟前
HTML5语义化标签:从div到article与section的进化之路
前端·html·html5
帅小伙―苏18 分钟前
力扣42接雨水
前端·算法·leetcode
糯米团子74924 分钟前
react速通-2
前端·react.js·前端框架
糯米团子74926 分钟前
react速通-3
javascript·react.js·前端框架
心连欣32 分钟前
从静态页面到动态交互:DOM操作的核心API解析
前端·javascript·api
橙某人35 分钟前
SSR页面上的按钮点不了?Nuxt 懒加载水合揭秘💧
前端·vue.js·nuxt.js
零瓶水Herwt40 分钟前
Javascript常用设计模式
javascript
PursuitofHappiness43 分钟前
2 tree-cli 的使用方法
前端
风骏时光牛马1 小时前
C Shell脚本编程与系统管理技术实践指南
javascript
烛衔溟1 小时前
TypeScript this 参数类型与全局 this
javascript·ubuntu·typescript