ReactJS自定义输入框:如何将邮箱标签嵌入输入框内
解决方案
要实现邮箱标签嵌入输入框内部的效果,我们需要调整DOM结构并配合CSS样式模拟输入框视觉效果,具体修改如下:
1. 修改React组件的DOM结构
将邮箱标签和输入框放入同一个容器内,同时修复原代码中的语法与事件问题,调整后的完整代码:
import React from "react"; import ReactDOM from "react-dom"; import "./styles.css"; class App extends React.Component { // 创建输入框ref(用于后续可能的DOM操作,可选) inputRef = React.createRef(); state = { items: [], value: "", error: null, editvalue:"" }; handleKeyDown = evt => { // 修复原数组语法错误:移除多余空引号 if (["Enter", "Tab", " "].includes(evt.key)) { evt.preventDefault(); const value = this.state.value.trim(); if (value && this.isValid(value)) { this.setState({ items: [...this.state.items, value], value: "" }); } } }; handleChange = evt => { this.setState({ value: evt.target.value, error: null }); }; handleDelete = item => { this.setState({ items: this.state.items.filter(i => i !== item) }); }; handleItemEdit = item =>{ const result = this.state.items.filter(values=>values!==item) this.setState({ value: item, error: null, items: result }); } handlePaste = evt => { evt.preventDefault(); const paste = evt.clipboardData.getData("text"); const emails = paste.match(/[\w\d\.-]+@[\w\d\.-]+\.[\w\d\.-]+/g); if (emails) { const toBeAdded = emails.filter(email => !this.isInList(email)); this.setState({ items: [...this.state.items, ...toBeAdded] }); } }; isValid(email) { let error = null; if (this.isInList(email)) { error = `${email} has already been added.`; } if (!this.isEmail(email)) { error = `${email} is not a valid email address.`; } if (error) { this.setState({ error }); return false; } return true; } isInList(email) { return this.state.items.includes(email); } isEmail(email) { return /[\w\d\.-]+@[\w\d\.-]+\.[\w\d\.-]+/.test(email); } render() { return ( <> {/* 新增外层容器,模拟输入框外观 */} <div className="input-container"> {this.state.items.map(item => ( <div className="tag-item" key={item} onClick={() => this.handleItemEdit(item)}> {item} <button type="button" className="button" onClick={(e) => { // 阻止事件冒泡,避免触发标签编辑 e.stopPropagation(); this.handleDelete(item); }} > × </button> </div> ))} <input ref={this.inputRef} className={"input " + (this.state.error && " has-error")} value={this.state.value} placeholder="Type or paste email addresses and press `Enter`..." onKeyDown={this.handleKeyDown} onChange={this.handleChange} onPaste={this.handlePaste} /> </div> {this.state.error && <p className="error">{this.state.error}</p>} </> ); } } const rootElement = document.getElementById("root"); ReactDOM.render(<App />, rootElement);
2. 调整CSS样式(styles.css)
通过样式让容器模拟输入框,同时让标签与输入框自然排列:
/* 外层容器:模拟输入框外观 */ .input-container { border: 1px solid #ccc; border-radius: 4px; padding: 8px; display: flex; flex-wrap: wrap; gap: 8px; align-items: center; min-height: 40px; transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; } /* 容器在输入框获焦时的高亮效果 */ .input-container:focus-within { border-color: #007bff; box-shadow: 0 0 0 0.2rem rgba(0,123,255,.25); } /* 邮箱标签样式 */ .tag-item { background-color: #e9ecef; padding: 4px 8px; border-radius: 4px; display: flex; align-items: center; gap: 4px; font-size: 14px; cursor: pointer; } /* 标签删除按钮 */ .tag-item .button { background: none; border: none; cursor: pointer; font-size: 16px; padding: 0; line-height: 1; color: #6c757d; } .tag-item .button:hover { color: #343a40; } /* 输入框样式:移除边框,与容器融合 */ .input { border: none; outline: none; flex: 1; min-width: 150px; font-size: 14px; padding: 4px 0; } /* 错误状态下的输入框文字颜色 */ .input.has-error { color: #dc3545; } /* 错误提示文字 */ .error { color: #dc3545; font-size: 14px; margin-top: 4px; }
关键修改说明
- 容器布局:用
input-container作为外层容器,通过flex布局实现标签与输入框横向排列,flex-wrap: wrap保证标签过多时自动换行。 - 视觉模拟:给容器设置边框、圆角,通过
:focus-within伪类实现输入框获焦时的容器高亮,模拟原生输入框交互。 - 输入框融合:移除输入框的边框与轮廓,设置
flex:1让它占据容器剩余空间,与容器融为一体。 - 事件修复:删除按钮添加
e.stopPropagation(),避免点击删除时触发标签的编辑事件。 - 语法修复:修正原代码中
handleKeyDown方法里的数组语法错误。
内容的提问来源于stack exchange,提问作者user15361826
相关产品推荐
相关产品推荐

