【问题标题】:React JS onClick event handlerReact JS onClick 事件处理程序
【发布时间】:2015-04-15 04:19:24
【问题描述】:

我有

var TestApp = React.createClass({
      getComponent: function(){
          console.log(this.props);
      },
      render: function(){
        return(
             <div>
             <ul>
                <li onClick={this.getComponent}>Component 1</li>
             </ul>
             </div>
        );
      }
});
React.renderComponent(<TestApp />, document.body);

我想为单击的列表元素的背景着色。我如何在 React 中做到这一点?

有点像

$('li').on('click', function(){
    $(this).css({'background-color': '#ccc'});
});

【问题讨论】:

    标签: javascript jquery reactjs


    【解决方案1】:

    为什么不:

    onItemClick: function (event) {
    
        event.currentTarget.style.backgroundColor = '#ccc';
    
    },
    
    render: function() {
        return (
            <div>
                <ul>
                    <li onClick={this.onItemClick}>Component 1</li>
                </ul>
            </div>
        );
    }
    

    如果您想对它更加 React-ive,您可能希望将所选项目设置为其包含 React 组件的状态,然后引用该状态来确定 render 中项目的颜色:

    onItemClick: function (event) {
    
        this.setState({ selectedItem: event.currentTarget.dataset.id });
        //where 'id' =  whatever suffix you give the data-* li attribute
    },
    
    render: function() {
        return (
            <div>
                <ul>
                    <li onClick={this.onItemClick} data-id="1" className={this.state.selectedItem == 1 ? "on" : "off"}>Component 1</li>
                    <li onClick={this.onItemClick} data-id="2" className={this.state.selectedItem == 2 ? "on" : "off"}>Component 2</li>
                    <li onClick={this.onItemClick} data-id="3" className={this.state.selectedItem == 3 ? "on" : "off"}>Component 3</li>
                </ul>
            </div>
        );
    },
    

    您希望将这些&lt;li&gt;s 放入一个循环中,并且您需要将li.onli.off 样式设置为您的background-color

    【讨论】:

    • React 中的手动 DOM 操作是一种反模式,只会导致更多问题。避免使用 event.currentTarget.style.backgroundColor = '#ccc'; 之类的东西,除非您真的了解自己在做什么(大多数时候,同时集成第三方小部件)。
    【解决方案2】:

    我能想到的两种方法是

    var TestApp = React.createClass({
        getComponent: function(index) {
            $(this.getDOMNode()).find('li:nth-child(' + index + ')').css({
                'background-color': '#ccc'
            });
        },
        render: function() {
            return (
                <div>
                  <ul>
                    <li onClick={this.getComponent.bind(this, 1)}>Component 1</li>
                    <li onClick={this.getComponent.bind(this, 2)}>Component 2</li>
                    <li onClick={this.getComponent.bind(this, 3)}>Component 3</li>
                  </ul>
                </div>
            );
        }
    });
    React.renderComponent(<TestApp /> , document.getElementById('soln1'));
    

    这是我个人最喜欢的。

    var ListItem = React.createClass({
        getInitialState: function() {
            return {
                isSelected: false
            };
        },
        handleClick: function() {
            this.setState({
                isSelected: true
            })
        },
        render: function() {
            var isSelected = this.state.isSelected;
            var style = {
                'background-color': ''
            };
            if (isSelected) {
                style = {
                    'background-color': '#ccc'
                };
            }
            return (
                <li onClick={this.handleClick} style={style}>{this.props.content}</li>
            );
        }
    });
    
    var TestApp2 = React.createClass({
        getComponent: function(index) {
            $(this.getDOMNode()).find('li:nth-child(' + index + ')').css({
                'background-color': '#ccc'
            });
        },
        render: function() {
            return (
                <div>
                 <ul>
                  <ListItem content="Component 1" />
                  <ListItem content="Component 2" />
                  <ListItem content="Component 3" />
                 </ul>
                </div>
            );
        }
    });
    React.renderComponent(<TestApp2 /> , document.getElementById('soln2'));
    

    这是DEMO

    我希望这会有所帮助。

    【讨论】:

    • 不建议在渲染函数中应用绑定,因为每次渲染组件时都会这样做。您可以将其移动到在生命周期开始时运行的某个函数
    • @jony89 同意如果.bind 不采用额外参数。但在第一种情况下确实如此。我认为没有其他方法
    • 有,创建三个不同的函数(由 getComponent.bind(this, 1) 的结果创建),虽然这个确定可以是一个决定(会为 2-3 个组件做,而不是20 - 除非它真的是性能问题并且很容易动态创建它)。
    【解决方案3】:

    这是您如何定义一个 react onClick 事件处理程序,它正在回答问题标题...使用 es6 语法

    import React, { Component } from 'react';
    
    export default class Test extends Component {
      handleClick(e) {
        e.preventDefault()
        console.log(e.target)
      }
    
      render() {
        return (
          <a href='#' onClick={e => this.handleClick(e)}>click me</a>
        )
      }
    }
    

    【讨论】:

    • bind 和箭头函数都不应该在 render 方法中使用,因为它们每次都会创建一个新函数。这会改变组件的状态,并且状态改变的组件总是会重新渲染。对于单个a,这没什么大不了的。对于带有可点击项目的生成列表,这很快就会变得很重要。这就是它被特别警告的原因。
    【解决方案4】:

    使用 ECMA2015。箭头函数使“this”更加直观。

    import React from 'react';
    
    
    class TestApp extends React.Component {
       getComponent(e, index) {
           $(e.target).css({
               'background-color': '#ccc'
           });
       }
       render() {
           return (
               <div>
                 <ul>
                   <li onClick={(e) => this.getComponent(e, 1)}>Component 1</li>
                   <li onClick={(e) => this.getComponent(e, 2)}>Component 2</li>
                   <li onClick={(e) => this.getComponent(e, 3)}>Component 3</li>
                 </ul>
               </div>
           );
       }
    });
    React.renderComponent(<TestApp /> , document.getElementById('soln1'));`
    

    【讨论】:

    • index 在这里什么都没做?
    • @northamerican - 不,它只是为了增加一些参数清晰度
    • 这实际上对性能不利,因为它会在每次渲染时创建一个新函数。见:stackoverflow.com/questions/36677733/…
    • 如果没有必要,请不要在 React 中使用 jQuery!
    【解决方案5】:

    如果您使用的是 ES6,这里有一些简单的示例代码:

    import React from 'wherever_react_is';
    
    class TestApp extends React.Component {
    
      getComponent(event) {
          console.log('li item clicked!');
          event.currentTarget.style.backgroundColor = '#ccc';
      }
    
      render() {
        return(
           <div>
             <ul>
                <li onClick={this.getComponent.bind(this)}>Component 1</li>
             </ul>
           </div>
        );
      }
    }
    
    export default TestApp;
    

    在 ES6 类主体中,函数不再需要 'function' 关键字,也不需要用逗号分隔。如果您愿意,也可以使用 => 语法。

    这是一个动态创建元素的示例:

    import React from 'wherever_react_is';
    
    class TestApp extends React.Component {
    
    constructor(props) {
      super(props);
    
      this.state = {
        data: [
          {name: 'Name 1', id: 123},
          {name: 'Name 2', id: 456}
        ]
      }
    }
    
      getComponent(event) {
          console.log('li item clicked!');
          event.currentTarget.style.backgroundColor = '#ccc';
      }
    
      render() {        
           <div>
             <ul>
             {this.state.data.map(d => {
               return(
                  <li key={d.id} onClick={this.getComponent.bind(this)}>{d.name}</li>
               )}
             )}
             </ul>
           </div>
        );
      }
    }
    
    export default TestApp;
    

    请注意,每个动态创建的元素都应该有一个唯一的引用“键”。

    此外,如果您想将实际数据对象(而不是事件)传递到 onClick 函数中,则需要将其传递到绑定中。例如:

    新增 onClick 功能:

    getComponent(object) {
        console.log(object.name);
    }
    

    传入数据对象:

    {this.state.data.map(d => {
        return(
          <li key={d.id} onClick={this.getComponent.bind(this, d)}>{d.name}</li>
        )}
    )}
    

    【讨论】:

    • 我正在尝试动态构建我的 li 项目,然后这看起来变得未定义,因此 onClick 函数会引发错误。
    • 我刚刚找到了一个类似的答案,您需要使用 .bind(this));在匿名函数的末尾,因为这里的 this 指的是窗口,直到您进行绑定...
    【解决方案6】:

    使用 React 元素 处理事件与处理事件非常相似 在 DOM 元素上。有一些语法差异:

    • React 事件使用 camelCase 命名,而不是小写。
    • 使用 JSX,您可以将函数作为事件处理程序传递,而不是字符串。

    正如 React 文档中提到的,它们在事件处理方面与普通 HTML 非常相似,但是 React 中的事件名称使用驼峰式,因为它们不是真正的 HTML,它们也是 JavaScript ,当我们以字符串格式传递函数调用时,您传递函数,它们是不同的,但概念非常相似......

    看下面的例子,注意事件传递给函数的方式:

    function ActionLink() {
      function handleClick(e) {
        e.preventDefault();
        console.log('The link was clicked.');
      }
    
      return (
        <a href="#" onClick={handleClick}>
          Click me
        </a>
      );
    }
    

    【讨论】:

      【解决方案7】:

      import React from 'react';
      
      class MyComponent extends React.Component {
      
        getComponent(event) {
            event.target.style.backgroundColor = '#ccc';
            
            // or you can write
            //arguments[0].target.style.backgroundColor = '#ccc';
        }
      
        render() {
          return(
             <div>
               <ul>
                  <li onClick={this.getComponent.bind(this)}>Component 1</li>
               </ul>
             </div>
          );
        }
      }
      
      export { MyComponent };  // use this to be possible in future imports with {} like: import {MyComponent} from './MyComponent'
      export default MyComponent;

      【讨论】:

      • 这似乎与 11 点答案基本相同,并重新提出了一个漂亮或问题 - 为什么?
      【解决方案8】:

      class FrontendSkillList extends React.Component {
        constructor() {
          super();
          this.state = { selectedSkill: {} };
        }
        render() {
          return (
            <ul>
              {this.props.skills.map((skill, i) => (
                  <li
                    className={
                      this.state.selectedSkill.id === skill.id ? "selected" : ""
                    }
                    onClick={this.selectSkill.bind(this, skill)}
                    style={{ cursor: "pointer" }}
                    key={skill.id}
                  >
                  {skill.name}
                  </li>
              ))}
            </ul>
          );
        }
      
        selectSkill(selected) {
          if (selected.id !== this.state.selectedSkill.id) {
            this.setState({ selectedSkill: selected });
          } else {
            this.setState({ selectedSkill: {} });
          }
        }
      }
      
      const data = [
        { id: "1", name: "HTML5" },
        { id: "2", name: "CSS3" },
        { id: "3", name: "ES6 & ES7" }
      ];
      const element = (
        <div>
          <h1>Frontend Skill List</h1>
          <FrontendSkillList skills={data} />
        </div>
      );
      ReactDOM.render(element, document.getElementById("root"));
      .selected {
        background-color: rgba(217, 83, 79, 0.8);
      }
      <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
      
      <div id="root"></div>

      @user544079 希望这个演示可以帮助:) 我建议通过切换类名来更改背景颜色。

      【讨论】:

        【解决方案9】:

        import React from 'react';
        
        class MyComponent extends React.Component {
        
          getComponent(event) {
              event.target.style.backgroundColor = '#ccc';
              
              // or you can write
              //arguments[0].target.style.backgroundColor = '#ccc';
          }
        
          render() {
            return(
               <div>
                 <ul>
                    <li onClick={this.getComponent.bind(this)}>Component 1</li>
                 </ul>
               </div>
            );
          }
        }
        
        export { MyComponent };  // use this to be possible in future imports with {} like: import {MyComponent} from './MyComponent'
        export default MyComponent;

        【讨论】:

        • 您能否通过解释如何解决此问题来为该代码提供更多上下文?
        【解决方案10】:

        您可以使用 React.createClone 方法。创建您的元素,而不是创建它的克隆。在克隆创建过程中,您可以注入道具。像这样注入一个 onClick : 方法属性

        { onClick : () =&gt; this.changeColor(originalElement, index) }

        changeColor 方法将设置带有副本的状态,允许您在此过程中设置颜色。

        render()
          {
            return(
              <ul>
        
                {this.state.items.map((val, ind) => {
                  let item = <li key={ind}>{val}</li>;
                  let props = { 
                    onClick: () => this.Click(item, ind),
                    key : ind,
                    ind
                  }
                  let clone = React.cloneElement(item, props, [val]);
                  return clone;
                })}
        
              </ul>
            )
          }

        【讨论】:

        • 完全不需要克隆。
        【解决方案11】:

        这是一种非标准(但并不罕见)的 React 模式,它不使用 JSX,而是将所有内容都内联。另外,它是 Coffeescript。

        执行此操作的“反应方式”将使用组件自己的状态:

        (c = console.log.bind console)

        mock_items: [
            {
                name: 'item_a'
                uid: shortid()
            }
            {
                name: 'item_b'
                uid: shortid()
            }
            {
                name: 'item_c'
                uid: shortid()
            }
        ]
        getInitialState: ->
            lighted_item: null
        render: ->
            div null,
                ul null,
                    for item, idx in @mock_items
                        uid = item.uid
                        li
                            key: uid
                            onClick: do (idx, uid) =>
                                (e) =>
                                    # justf to illustrate these are bound in closure by the do lambda,
                                    c idx
                                    c uid
                                    @setState
                                        lighted_item: uid
                            style:
                                cursor: 'pointer'
                                background: do (uid) =>
                                    c @state.lighted_item
                                    c 'and uid', uid
                                    if @state.lighted_item is uid then 'magenta' else 'chartreuse'
                                # background: 'chartreuse'
                            item.name
        

        这个例子有效——我在本地测试过。 您可以在my github 上查看此示例代码。 最初 env 仅用于我自己的白板研发目的,但我为此将其发布到 Github。它可能会在某个时候被重写,但您可以查看 2016 年 9 月 8 日的提交以查看此内容。

        更一般地说,如果你想了解这种用于 React 的 CS/no-JSX 模式是如何工作的,请查看最近的一些工作 here。我可能有时间为这个应用创意完全实现 POC,其中的堆栈包括 NodeJS、Primus、Redis 和 React。

        【讨论】:

        • 背景不必是do lambda:此表达式也适用:background: if @state.lighted_item is uid then 'magenta' else 'chartreuse'
        • 你好如何在浏览器控制台上查看onclick?
        • 你为什么要使用 CoffeeScript 来回答一个没有以任何方式提及它的问题?这没有任何意义,并且可能会使提问者更难阅读答案,因为他可能不知道/不喜欢 CoffeeScript。显然是投反对票。
        • 不,但它是建立在语言之上的东西,绝对不是标准的,需要安装和编译。当零提示他们在他们的项目中使用咖啡脚本时,用咖啡脚本写你的答案确实是一个糟糕的选择
        • Coffeescript 只是 js 之上的一层。 FTFY。
        猜你喜欢
        • 2021-06-27
        • 2020-04-09
        • 2019-02-17
        • 2018-01-25
        • 2017-03-14
        • 1970-01-01
        • 2017-06-16
        • 1970-01-01
        相关资源
        最近更新 更多