mer*_*ilj 9 javascript jsx reactjs semantic-ui-react
我正在尝试在React上关注/突出显示输入文本onClick.它按预期工作,但仅适用于渲染数组中的最后一个元素.我尝试了几种不同的方法,但它们都做了完全相同的事情.以下是我的两个例子:
export default class Services extends Component {
handleFocus(event) {
event.target.select()
}
handleClick() {
this.textInput.focus()
}
render() {
return (
<div>
{element.sources.map((el, i) => (
<List.Item key={i}>
<Segment style={{marginTop: '0.5em', marginBottom: '0.5em'}}>
<Input fluid type='text'
onFocus={this.handleFocus}
ref={(input) => { this.textInput = input }}
value='text to copy'
action={
<Button inverted color='blue' icon='copy' onClick={() => this.handleClick}></Button>
}
/>
</Segment>
</List.Item>
))}
</div>
)
}
Run Code Online (Sandbox Code Playgroud)
如果只有一个元素被渲染,它会将文本聚焦在输入中,但如果有多个元素,则每个元素的按钮单击仅选择最后一个元素的输入.这是另一个例子:
export default class Services extends Component {
constructor(props) {
super(props)
this._nodes = new Map()
this._handleClick = this.handleClick.bind(this)
}
handleFocus(event) {
event.target.select()
}
handleClick(e, i) {
const node = this._nodes.get(i)
node.focus()
}
render() {
return (
<div>
{element.sources.map((el, i) => (
<List.Item key={i}>
<Segment style={{marginTop: '0.5em', marginBottom: '0.5em'}}>
<Input fluid type='text'
onFocus={this.handleFocus}
ref={c => this._nodes.set(i, c)}
value='text to copy'
action={
<Button inverted color='blue' icon='copy' onClick={e => this.handleClick(e, i)}></Button>
}
/>
</Segment>
</List.Item>
))}
</div>
)
}
Run Code Online (Sandbox Code Playgroud)
这两种方法基本上都以相同的方式响应.我需要handleClick输入焦点来适用于每个动态渲染的元素.任何意见是极大的赞赏.提前致谢!
该Input
组件是从Semantic UI React导入的,我的应用程序中没有其他实现
更新 感谢大家的答案.这两种方法在单个循环元素渲染中都很有效,但现在我正在尝试使用多个父元素来实现它.例如:
import React, { Component } from 'react'
import { Button, List, Card, Input, Segment } from 'semantic-ui-react'
export default class ServiceCard extends Component {
handleFocus(event) {
event.target.select()
}
handleClick = (id) => (e) => {
this[`textInput${id}`].focus()
}
render() {
return (
<List divided verticalAlign='middle'>
{this.props.services.map((element, index) => (
<Card fluid key={index}>
<Card.Content>
<div>
{element.sources.map((el, i) => (
<List.Item key={i}>
<Segment>
<Input fluid type='text'
onFocus={this.handleFocus}
ref={input => { this[`textInput${i}`] = input }}
value='text to copy'
action={
<Button onClick={this.handleClick(i)}></Button>
}
/>
</Segment>
</List.Item>
))}
</div>
</Card.Content>
</Card>
))}
</List>
)
}
Run Code Online (Sandbox Code Playgroud)
现在,在修改后的代码中,您的方法适用于一个Card
元素,但是当有多个Card
元素时,它仍然只适用于最后一个元素.两者Input
Buttons
分别用于输入,但仅用于Card
渲染的最后一个元素.
ref
如您所知,您正在设置一个循环内部,通过关键字将ref
其设置为class
via this
。这意味着您要设置多个,refs
但要覆盖中的一个class
。
一种解决方案(不是理想的解决方案)是用不同的方式命名它们,也许在每个ref
名称上添加密钥:
ref={input => {
this[`textInput${i}`] = input;
}}
Run Code Online (Sandbox Code Playgroud)
并且当您针对的onClick
事件定位时,Button
应使用相同的键作为参数:
action={
<Button
inverted
color="blue"
icon="copy"
onClick={this.handleClick(i)}
>
Focus
</Button>
}
Run Code Online (Sandbox Code Playgroud)
现在,click事件应该更改并接受id
作为参数并触发相关事件ref
(我在这里使用currying):
handleClick = (id) => (e) => {
this[`textInput${id}`].focus();
}
Run Code Online (Sandbox Code Playgroud)
请注意,这是一个简单的解决方案,但不是理想的解决方案,因为我们在每个渲染器上创建一个函数的新实例,因此我们传递了一个新的prop,该prop可以中断react的差异算法(更好,更“ react'ish”下一步)。
优点:
缺点:
这是完整的代码:
class Services extends React.Component {
handleFocus(event) {
event.target.select();
}
handleClick = id => e => {
this[`textInput${id}`].focus();
};
render() {
return (
<div>
{sources.map((el, i) => (
<List.Item key={i}>
<Segment style={{ marginTop: "0.5em", marginBottom: "0.5em" }}>
<Input
fluid
type="text"
onFocus={this.handleFocus}
ref={input => {
this[`textInput${i}`] = input;
}}
value="text to copy"
action={
<Button
inverted
color="blue"
icon="copy"
onClick={this.handleClick(i)}
>
Focus
</Button>
}
/>
</Segment>
</List.Item>
))}
</div>
);
}
}
render(<Services />, document.getElementById("root"));
Run Code Online (Sandbox Code Playgroud)
更好,更“反应”的解决方案是使用组件组合或包装的HOC Button
并注入一些简单的逻辑,如传递id
父级而不是使用2个函数。
优点:
缺点:
更多代码编写
维护/测试等的另一个组件。
一个工作示例
完整代码:
class MyButton extends React.Component {
handleClick = (e) => {
this.props.onClick(this.props.id)
}
render() {
return (
<Button
{...this.props}
onClick={this.handleClick}
>
{this.props.children}
</Button>
)
}
}
class Services extends React.Component {
constructor(props){
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleFocus(event) {
event.target.select();
}
handleClick(id){
this[`textInput${id}`].focus();
};
render() {
return (
<div>
{sources.map((el, i) => (
<List.Item key={i}>
<Segment style={{ marginTop: "0.5em", marginBottom: "0.5em" }}>
<Input
fluid
type="text"
onFocus={this.handleFocus}
ref={input => {
this[`textInput${i}`] = input;
}}
value="text to copy"
action={
<MyButton
inverted
color="blue"
icon="copy"
onClick={this.handleClick}
id={i}
>
Focus
</MyButton>
}
/>
</Segment>
</List.Item>
))}
</div>
);
}
}
render(<Services />, document.getElementById("root"));
Run Code Online (Sandbox Code Playgroud)
编辑
作为编辑的后续步骤:
但是当有多个Card元素时,它仍然仅适用于最后一个。
发生这种情况的原因与以前相同i
,两个数组都使用相同的原因。
这是一个简单的解决方案,请同时使用index
和i
作为您的ref
名字。
设置ref
名称:
ref={input => { this[`textInput${index}${i}`] = input }}
Run Code Online (Sandbox Code Playgroud)
将名称传递给处理程序:
<Button onClick={this.handleClick(`${index}${i}`)}></Button>
Run Code Online (Sandbox Code Playgroud)
我已经修改了问题,并提供了第二个解决方案,它被认为是最佳实践。再次阅读我的答案,然后看看不同的方法。
归档时间: |
|
查看次数: |
10275 次 |
最近记录: |