【问题标题】:React - changing the background of a single span class not workingReact - 更改单个跨度类的背景不起作用
【发布时间】:2019-01-14 08:24:23
【问题描述】:

我是 React 的新手,所以如果问题或我想要实现的事情很奇怪,我深表歉意(请告诉我是否有更好/更合乎逻辑的方法来做到这一点)。

我在我的 React 应用程序中使用 List Fabric React 组件,该组件基于此处的 ListGridExample 组件: https://developer.microsoft.com/en-us/fabric#/components/list

我已经设置好了,但我似乎无法完成以下操作:

当单击List 组件中的span class(实际上是一个项目)时,我想将其更改为background color,为此我已按照以下帖子中的说明进行操作: https://forum.freecodecamp.org/t/react-js-i-need-a-button-color-to-change-onclick-but-cannot-determine-how-to-properly-set-and-change-state-for-that-component/45168

这是一个相当简单的示例,但这会将我所有的grid cells / span classes 更改为蓝色,而不仅仅是单击的那个。有没有办法让点击的跨度类改变它的背景?

初始状态:

点击一个跨度类后的状态(错误):

实现代码(省略了一些不必要的代码):

class UrenBoekenGrid extends React.Component {

    constructor(props) {
      super(props);

      this.state = {
        bgColor: 'red'
     }

    }

    render() {
      return (
        <FocusZone>
          <List

            items={[
                {
                key: '#test1',
                name: 'test1',
                },
                {
                name: 'test2',
                key: '#test2',
                },
                {
                name: 'test3',
                key: '#test3',
                },
                {
                name: 'test4',
                key: '#test4',
                },

                ..... up to 32 items

            ]}

            onRenderCell={this._onRenderCell}

          />
        </FocusZone>
      );
    }


    changeColor(item){
        this.setState({bgColor: 'blue'});

        console.log('clicked item == ' + item.name)

      }



    _onRenderCell = (item, index) => {

        return (
          <div
            className="ms-ListGridExample-tile"
            data-is-focusable={true}
            style={{
              width: 100 / this._columnCount + '%',
              height: this._rowHeight * 1.5,
              float: 'left'
            }}
          >
            <div className="ms-ListGridExample-sizer">
              <div className="msListGridExample-padder">

                {/* The span class with the click event: */}
                <span className="ms-ListGridExample-label" onClick={this.changeColor.bind(this, item)} style={{backgroundColor:this.state.bgColor}}>{`item ${index}`}</span>
                <span className="urenboeken-bottom"></span>

              </div>
            </div>
          </div>
        );
    };


}

我现在已将click event 附加到span class 本身,但我认为将click event 放在item(s)(数组)本身上更符合逻辑,但是我找不到方法实现这一点。

----更新----

@peetya 回答似乎是要走的路,因为@Mario Santini 回答只是更新一个单元格,如果单击另一个单元格,则前一个单元格恢复正常并失去颜色。

所以我所做的是将items array 添加到state 并将bgColor 属性添加到它们:

this.state = {
        items: [
            {
                key: '#test1',
                name: 'test1',
                bgColor: 'blue',
            },
            {
                name: 'test2',
                key: '#test2',   
                bgColor: 'blue',    
            },
            {
                name: 'test3',
                key: '#test3',
                bgColor: 'blue',    
            },
            {
                name: 'test4',
                key: '#test4',
                bgColor: 'blue',    
            },
        ],
     }

现在在我的List 渲染中,我已将项目设置为state items 数组并在_onRenderCell 函数中添加了onClick 事件:

render() {
      return (
        <FocusZone>
          <List

            items={this.state.items}

            getItemCountForPage={this._getItemCountForPage}
            getPageHeight={this._getPageHeight}
            renderedWindowsAhead={4}
            onRenderCell={this._onRenderCell}

          />
        </FocusZone>
      );
    }


_onRenderCell = (item, index) => {

        return (
          <div
            className="ms-ListGridExample-tile"
            data-is-focusable={true}
            style={{
              width: 100 / this._columnCount + '%',
              height: this._rowHeight * 1.5,
              float: 'left'
            }}
          >
            <div className="ms-ListGridExample-sizer">
              <div className="msListGridExample-padder">

                <span className="ms-ListGridExample-label" 
                     onClick={this.onClick(item.name)} 
                     style={{backgroundColor: item.bgColor}}
                >
                    {`item ${index}`}
                </span>

                <span className="urenboeken-bottom"></span>



              </div>
            </div>
          </div>
        );
    };

问题是我无法在_onRenderCell 函数中添加onClick event,因为这会出现以下错误:

我想保留 Fabric List component,因为它还具有渲染/调整屏幕尺寸的功能,完全删除列表组件并用 @peetya 建议的工作替换它:

render() {
        <div>
            {this.state.items.map(item => (
                <div onClick={() => this.onClick(item.name)} style={{backgroundColor: item.bgColor}}>
                    {item.name}
                </div>
            ))}
        </div>
    }

但这也将删除 List 组件功能及其 responsive 函数。

所以我的最后一个想法是用整个 onClick div 替换 Listitems 并删除 _onRenderCell 函数本身,但这会使页面空白(看不到单元格都没有了..):

  render() {
      return (
        <FocusZone>
          <List

            items={this.state.items.map(item => (
                <div onClick={() => this.onClick(item.name)} style={{backgroundColor: item.bgColor}}>
                    {item.name}
                </div>
            ))}

            getItemCountForPage={this._getItemCountForPage}
            getPageHeight={this._getPageHeight}
            renderedWindowsAhead={4}
           // onRenderCell={this._onRenderCell}

          />
        </FocusZone>
      );
    }

我认为也许 css ms-classes / div 也应该在那里,因为它们具有高度/宽度属性,但添加它们(就像在 _onRenderCell 函数中一样)没有任何区别,页面是还是空白。

【问题讨论】:

    标签: javascript reactjs react-native fabricjs


    【解决方案1】:

    问题是您将背景颜色存储在 Grid 的状态中,并将此状态分配给网格的每个元素,因此如果您更新状态,它将影响每个元素。最好的方法是为 Grid 元素创建一个单独的组件并将它们自己的状态存储在其中,或者如果您只想使用一个状态然后将 items 数组存储在状态中并为它们添加一个新的 bgColor 属性所以如果你只想改变一项的背景颜色,你需要为items数组的特定对象调用setEstate。

    这是一个小例子(我没有测试过):

    class UrenBoekenGrid extends React.Component {
        constructor(props) {
            super(props);
    
            this.state = {
                items: [
                    {
                        key: '#test1',
                        name: 'test1',
                        bgColor: 'blue',
                    },
                ],
            };
        }
    
        onClick(name) {
            this.setState(prevState => ({
                items: prevState.items.map(item => {
                    if (item.name === name) {
                        item.bgColor = 'red';
                    }
    
                    return item;
                })
            }))
        }
    
        render() {
            <div>
                {this.state.items.map(item => (
                    <div onClick={() => this.onClick(item.name)} style={{backgroundColor: item.bgColor}}>
                        {item.name}
                    </div>
                ))}
            </div>
        }
    }
    

    【讨论】:

    • 非常感谢您的回答,这似乎是要走的路,但是我似乎无法在现有的List component 中实施您的解决方案。我已经用遇到的问题更新了我的主要帖子(在更新部分)。
    • 不客气 :) 似乎您正在更新 render()constructor() 函数之一中的状态,它会导致无限循环。你能展示你的构造函数和/或渲染方法吗?
    • 这可能是导致问题的原因:onClick={this.onClick(item.name)} 。在这里,您在渲染组件时调用 onClick 方法。尝试将其更改为onClick={() =&gt; this.onClick(item.name)}
    • 你是绝对正确的。再次感谢您,用onClick={() =&gt; this.onClick(item.name)} 替换onClick={this.onClick(item.name)} 就可以了!愚蠢的我错过了!
    【解决方案2】:

    实际上,您正在更改所有 span 元素的颜色,因为您将每个 span 的样式设置为状态变量 bgColor

    Insteas,您应该保存单击的项目,并据此决定颜色:

    this.state = {
        bgColor: 'red',
        clickedColor: 'blue
    }
    

    在构造函数中。

    然后在点击处理程序中:

    changeColor(item){
        this.setState({selected: item.name});
    
        console.log('clicked item == ' + item.name)
    }
    

    所以在渲染器中(我只是放了相关部分):

    <span ... style={{backgroundColor: (item.name === this.state.selected ? this.state.clickedColor : this.state.bgColor)}}>{`item ${index}`}</span>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-03-15
      • 1970-01-01
      • 1970-01-01
      • 2023-01-23
      • 2020-09-12
      • 2014-04-09
      • 2016-11-28
      • 1970-01-01
      相关资源
      最近更新 更多