组件功能描述
本组件结合antd中的Form和Input组件实现一个变量输入框,
- 该输入框可插入多个变量,其中变量格式为[X1]、[X2]、[X3]、[X4]、[X5]
- 删除变量右侧的‘]’符号可整个删除该变量;
- 删除变量后,再次插入变量时会计算变量模版中的最小变量值,插入最小变量值,如目前输入框内有变量[X1]、[X2]、[X3],删除变量[X2]后再次插入变量会插入[X2],而不是[X4];
- 插入变量和输入框输入操作会进行格式校验,不允许在变量内插入其他值,会报错提示:不能对变量标志中进行插入变量!;
- 插入变量时进行数量校验,不可超过最大变量数,超出会提示:最多插入5个变量!;
- 该组件主要提供实现思路,大家可根据自己的需求调整组件中变量格式和个数,需注意必须明确变量格式和数量;
组件效果
视频效果
插入变量效果图
图片示意图
组件使用示例
// 在标题内插入变量
<VariableInput
label="标题"
name="title"
value='[X1]啦,这里是[X2]'
variableChange={(value: string) => console.log(value)}
/>
组件实现代码
import { PlusCircleOutlined } from "@ant-design/icons";
import { Input, Form, message } from "antd";
import { TextAreaRef } from "antd/lib/input/TextArea";
import React, { FC, useEffect, useRef, useState } from "react";
import s from './index.module.less';
interface VariableInputProps {
value: string; // 输入框初始默认值
label: string; // FormItem 标题
name: string; // FormItem 参数名称
variableChange: (value: string) => void; // 输入框变化的回调函数
}
export const VARIABLE_REG = /\[X(.*?)\]/g; // 正则匹配变量[X..]
export const VARIABLE_ARRAY = ['[X1]', '[X2]', '[X3]', '[X4]', '[X5]']; // 明确的所有变量模版
const VariableInput: FC<VariableInputProps> = ({ value, label, name, variableChange }) => {
const [inputValue, setInputValue] = useState<string>('');
const inputRef = useRef<TextAreaRef>(null);
const [variableArray, setVariableArray] = useState<string[]>([]);
useEffect(() => {
const variableArr = value.match(VARIABLE_REG) || [];
setInputValue(value);
setVariableArray(variableArr);
}, [value]);
// 获取插入变量的起始Index
const getInsertInitialIndex = () => {
if (variableArray.length === 0) return 1;
const variableIndexArray = variableArray.map(itm => {
const index = itm.match(/\d/);
if (Array.isArray(index) && index.length > 0) {
return Number(index[0]);
}
});
const arr = [1, 2, 3, 4, 5].filter(itm => !variableIndexArray.includes(itm));
return arr[0]
}
// 插入变量
const insertVariable = () => {
const initialIndex = getInsertInitialIndex()
const textareaElement = inputRef?.current?.resizableTextArea?.textArea; // 获取textArea元素
const cursorPosition = textareaElement?.selectionStart || 0; // 获取光标起始位置
const previousText = inputValue.substr(0, cursorPosition); // 获取变量前文本
const followingText = inputValue.substr(cursorPosition); // 获取变量后文本
const initialValues = `${previousText}[X${initialIndex}]${followingText}`;
// 获取插入变量
const variableArr = initialValues.match(VARIABLE_REG) || [];
if (variableArr.length > 5) {
return message.error('最多插入5个变量!');
}
const isCompliant = variableArr.every(itm => VARIABLE_ARRAY.includes(itm))
if (!isCompliant) {
return message.error('不能对变量标志中进行插入变量!');
}
setInputValue(initialValues);
setVariableArray(variableArr);
variableChange?.(initialValues);
// 插入操作完成后 将光标定位到插入内容的后面
setTimeout(() => {
inputRef?.current?.focus();
});
};
// 键盘输入
const handleChangeInput = (e: any) => {
const initialValues = e?.target?.value;
const reg = /\[X([^[\]]*?)\]/g;
// 当前输入框内匹配的插入变量
const variableArr = initialValues.match(reg) || [];
// 判断是否合规
const isCompliant = variableArr.every((itm: string) => VARIABLE_ARRAY.includes(itm))
if (!isCompliant) {
return message.error('不能对变量标志中进行插入变量!');
}
// 判断是否手动删除变量,当前输入框内的变量数组与原变量数组对比,如果缺了就说明删除了一个变量
const deleteVariable = variableArray.filter((itm: string) => !variableArr.includes(itm));
let deletedString = initialValues;
if (deleteVariable.length > 0) {
deletedString = inputValue.replace(deleteVariable[0], '');
}
setVariableArray(variableArr);
setInputValue(deletedString);
variableChange?.(deletedString);
}
return (
<React.Fragment>
<Form.Item label={label} name={name}>
<div className={s.variableModule}>
<div className={s.insertBtnBox}>
<PlusCircleOutlined style={{ cursor: 'pointer' }} onClick={insertVariable} />
<span style={{ cursor: 'pointer' }} onClick={insertVariable}>插入变量</span>
</div>
<Input.TextArea value={inputValue} ref={inputRef} onChange={handleChangeInput} />
</div>
</Form.Item>
</React.Fragment>
);
}
export default VariableInput;
.variableModule {
width: 600px;
:global {
.ant-input {
border: 1px solid #eceef1;
border-top: none;
}
}
}
.insertBtnBox {
display: flex;
align-items: center;
padding: 4px 12px;
gap: 4px;
height: 32px;
background: #f8f9fa;
border-bottom: 1px solid #eceef1;
color: #0084FF;
}
查看视频效果图代码
视频效果图中效果更加丰满一点,输入框下还包括一个与输入框内的变量联动的表格,表格内可实现删除变量,设置变量对应的值,右侧还有一个预览效果,由于实现功能比较丰满,逻辑更为复杂,包括一个变量输入组件+可编辑表格组件 = 组合效果,具体效果图中的实现代码可至我的git仓库内查看,有问题欢迎私信,我会在空闲时间100%解答奥~♥️