React中基于react-multi-email实现多邮箱字段的编辑功能
给react-multi-email添加邮箱编辑功能的解决方案
由于react-multi-email本身没有内置编辑功能,我们可以通过自定义getLabel属性结合组件内部状态,实现点击标签修改邮箱的功能,具体实现步骤如下:
1. 扩展组件状态
首先在组件的状态接口和初始state中,添加用于跟踪编辑状态的变量:
interface IState { emails: string[]; editingIndex: number; // 当前正在编辑的邮箱索引,-1表示无编辑状态 editValue: string; // 编辑时的临时输入值 } class App extends React.Component<IProps, IState> { state = { emails: [], editingIndex: -1, editValue: "" }; }
2. 编写编辑相关的处理函数
添加三个核心处理函数,分别负责进入编辑状态、保存编辑结果、取消编辑:
// 进入编辑状态,记录当前索引和原邮箱内容 handleEditStart = (index: number, email: string) => { this.setState({ editingIndex: index, editValue: email }); }; // 保存编辑后的邮箱,先验证格式再更新列表 handleEditSave = (index: number) => { const { emails, editValue } = this.state; const isValidEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(editValue); if (isValidEmail) { const newEmails = [...emails]; newEmails[index] = editValue; this.setState({ emails: newEmails, editingIndex: -1, editValue: "" }); } else { alert("请输入有效的邮箱地址"); this.setState({ editingIndex: -1, editValue: "" }); } }; // 取消编辑,重置状态 handleEditCancel = () => { this.setState({ editingIndex: -1, editValue: "" }); };
3. 自定义标签渲染逻辑(修改getLabel)
在getLabel回调中,根据当前编辑状态切换显示普通标签或编辑输入框:
getLabel={(email: string, index: number, removeEmail: (index: number) => void) => { const { editingIndex, editValue } = this.state; // 处于编辑状态时,显示输入框 if (editingIndex === index) { return ( <div data-tag key={index} style={{ display: "inline-flex", alignItems: "center", gap: "4px", margin: "4px" }}> <input type="text" value={editValue} onChange={(e) => this.setState({ editValue: e.target.value })} onKeyDown={(e) => { e.key === "Enter" && this.handleEditSave(index); e.key === "Escape" && this.handleEditCancel(); }} onBlur={() => this.handleEditSave(index)} autoFocus style={{ padding: "4px 6px", border: "1px solid #ccc", borderRadius: "4px" }} /> <span onClick={() => this.handleEditCancel()} style={{ cursor: "pointer", padding: "0 4px" }}>✕</span> </div> ); } // 非编辑状态,显示带删除、编辑按钮的普通标签 return ( <div data-tag key={index} style={{ display: "inline-flex", alignItems: "center", gap: "4px", margin: "4px" }}> {email} <span data-tag-handle onClick={() => removeEmail(index)} style={{ cursor: "pointer", padding: "0 4px" }}>×</span> <span onClick={() => this.handleEditStart(index, email)} style={{ cursor: "pointer", padding: "0 4px", fontSize: "12px" }}>✏️</span> </div> ); }}
完整修改后的代码
import * as React from "react"; import { render } from "react-dom"; import { ReactMultiEmail } from "react-multi-email"; import "react-multi-email/style.css"; const styles = { fontFamily: "sans-serif", width: "500px", border: "1px solid #eee", background: "#f3f3f3", padding: "25px", margin: "20px" }; interface IProps {} interface IState { emails: string[]; editingIndex: number; editValue: string; } class App extends React.Component<IProps, IState> { state = { emails: [], editingIndex: -1, editValue: "" }; handleEditStart = (index: number, email: string) => { this.setState({ editingIndex: index, editValue: email }); }; handleEditSave = (index: number) => { const { emails, editValue } = this.state; const isValidEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(editValue); if (isValidEmail) { const newEmails = [...emails]; newEmails[index] = editValue; this.setState({ emails: newEmails, editingIndex: -1, editValue: "" }); } else { alert("请输入有效的邮箱地址"); this.setState({ editingIndex: -1, editValue: "" }); } }; handleEditCancel = () => { this.setState({ editingIndex: -1, editValue: "" }); }; render() { const { emails } = this.state; return ( <div style={styles}> <h3>react-multi-email 带编辑功能</h3> <ReactMultiEmail placeholder="Input your Email Address" emails={emails} onChange={(_emails: string[]) => { this.setState({ emails: _emails }); }} getLabel={(email: string, index: number, removeEmail: (index: number) => void) => { const { editingIndex, editValue } = this.state; if (editingIndex === index) { return ( <div data-tag key={index} style={{ display: "inline-flex", alignItems: "center", gap: "4px", margin: "4px" }}> <input type="text" value={editValue} onChange={(e) => this.setState({ editValue: e.target.value })} onKeyDown={(e) => { e.key === "Enter" && this.handleEditSave(index); e.key === "Escape" && this.handleEditCancel(); }} onBlur={() => this.handleEditSave(index)} autoFocus style={{ padding: "4px 6px", border: "1px solid #ccc", borderRadius: "4px" }} /> <span onClick={() => this.handleEditCancel()} style={{ cursor: "pointer", padding: "0 4px" }}>✕</span> </div> ); } return ( <div data-tag key={index} style={{ display: "inline-flex", alignItems: "center", gap: "4px", margin: "4px" }}> {email} <span data-tag-handle onClick={() => removeEmail(index)} style={{ cursor: "pointer", padding: "0 4px" }}>×</span> <span onClick={() => this.handleEditStart(index, email)} style={{ cursor: "pointer", padding: "0 4px", fontSize: "12px" }}>✏️</span> </div> ); }} /> <br /> <p>当前邮箱列表: {emails.join(", ")}</p> </div> ); } } render(<App />, document.getElementById("root"));
功能说明
- 点击标签上的✏️图标,进入编辑状态,原邮箱内容转为可编辑输入框
- 编辑时按
Enter键或点击输入框外部,自动验证邮箱格式并保存修改 - 按
Escape键或点击输入框旁的✕,取消编辑并恢复原邮箱内容 - 原有的删除标签功能保持正常使用
内容的提问来源于stack exchange,提问作者user15361826
相关产品推荐
相关产品推荐

