通过 onClick 删除 React.js 中的段落?

Strikethrough a Paragraph in React.js via onClick?

我已经准备好撕掉头发了。所以我在 Javascript class 中的最终项目是学习 React.js 的实验性项目,您可以在其中列一个基本的待办事项列表。我完成了所有工作并开始工作,我可以让它正确地添加东西。但我的最后一个障碍是让点击按钮上的打印段落会导致他们给打印的段落添加删除线 属性,可以通过再次点击它来撤消。

我到处都看过,我试过这里的其他例子,没有我能想到的是删除线发生。我尝试了一个基本的 Javascript 函数,如果这是一个 HTML/non-react 文件,它会做我想做的事,但是当我试图把它放进去时它会破坏反应页面。所以我花了很长时间在一个教程试图弄清楚该怎么做,我也许想出了正确方向的步骤?但我仍然无法让任何事情发生,我不知道如何为此建立一个 onclick。

import React from 'react';
import './App.css';

class App extends React.Component {
    setCurrentToDoItem = (toDoItem) => {
        console.log("toDoItem", toDoItem);

        this.setState({
            currentToDoItem: toDoItem
        });
    };

    saveToDoListItem = (toDoItem) => {
        this.setState({
            toDoList: [...this.state.toDoList,
                toDoItem]


        });

    };

    constructor(props) {
        super(props);

        this.state = {
            currentToDoItem: null,
            toDoList: [],
            strikeThrough: []
        };
    }
    render() {
        return (

            <div>
                <h1>To Do List</h1>
                <label>To Do Item: </label>
                <input
                    onChange={(event) => this.setCurrentToDoItem(event.target.value)}>
                </input>
                <button onClick={() => this.saveToDoListItem(this.state.currentToDoItem)}>
                    <p>Add Item</p>
                </button>
                <p>{this.state.currentToDoItem}</p>


                <div>
                    <p>To Do Items</p>
                    {
                        this.state.toDoList.map((item, index) => <p key={index}>{item} </p>)
                    }
                </div>
            </div>

        );
    }
}

export default App;

这是我的 App.js 代码。如您所见,其他一切都应该工作正常,但我不知道如何向 this.state.toDoList.map((item, index) => <p key={index}>{item} </p>) 位的结果添加删除线效果,就像我在正常 javascript 中使用函数一样。如何通过 onclick 使打印的线条成为删除线,然后如何通过再次单击取消删除线? (我假设有第二次点击)我真的只需要知道如何通过这个获得一个有效的删除线,因为其他一切都非常有效。

查看此解决方案https://codesandbox.io/s/crazy-kare-go2vf

我已经修改了您的代码以实现所需的功能。 此代码完全符合您的要求。

最舒适的方法之一就是按照评论中的建议进行操作。一个真正快速的实现方法是切换 class 列表。在下面的代码中,我添加了一个函数 crossLine 来切换 class 名称 "crossed-line" 并在映射的待办事项上添加事件侦听器(在 render 函数中)。然后在你的 App.css 添加一行

.crossed-line {
    text-decoration: line-through;
}

这是您编辑的组件代码。

class App extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            currentToDoItem: null,
            toDoList: [],
            strikeThrough: []
        };
    }
    setCurrentToDoItem = toDoItem => {
        this.setState({
            currentToDoItem: toDoItem
        });
    };

    saveToDoListItem = toDoItem => {
        this.setState({
            toDoList: [...this.state.toDoList, toDoItem]
        });
    };

    crossLine = event => {
        const element = event.target;
        element.classList.toggle("crossed-line");
    };

    render() {
        return (
            <div>
                <h1>To Do List</h1>
                <label>To Do Item: </label>
                <input
                    onChange={event =>
                        this.setCurrentToDoItem(event.target.value)
                    }
                />
                <button
                    onClick={() =>
                        this.saveToDoListItem(this.state.currentToDoItem)
                    }
                >
                    <p>Add Item</p>
                </button>
                <p>{this.state.currentToDoItem}</p>

                <div>
                    <p>To Do Items</p>
                    {this.state.toDoList.map((item, index) => {
                        return (
                            <p onClick={this.crossLine} key={index}>
                                {item}{" "}
                            </p>
                        );
                    })}
                </div>
            </div>
        );
    }
}

如评论所述,您必须按住句柄单击并添加 class 以使用 CSS 添加删除线。

为此,我已将您的 JSX 更新为:

<p onClick={ () => this.handleClick(index) } className={ item.isComplete ? 'completed' : '' } key={index}>{item.value} </p>

toDoItem 从字符串到对象的签名:

{
    value: string;
    isComplete: boolean
}

基于这个标志,我添加了 class。

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      currentToDoItem: null,
      toDoList: [],
      strikeThrough: []
    };

    this.setCurrentToDoItem = this.setCurrentToDoItem.bind(this);
    this.saveToDoListItem = this.saveToDoListItem.bind(this);
    this.handleClick = this.handleClick.bind(this);
  }

  setCurrentToDoItem(toDoItem) {
    this.setState({
      currentToDoItem: toDoItem
    });
  }

  saveToDoListItem(toDoItem) {
    this.setState({
      toDoList: [...this.state.toDoList, {
        value: toDoItem,
        isComplete: false
      }]
    });
  }

  handleClick(index) {
    const {
      toDoList
    } = this.state;
    toDoList[index].isComplete = !toDoList[index].isComplete;
    this.setState({
      toDoList
    });
  }

  render() {
    return (
      <div>
          <h1>To Do List</h1>
          <label>To Do Item: </label>
          <input
              onChange={(event) => this.setCurrentToDoItem(event.target.value)}>
          </input>
          <button onClick={() => this.saveToDoListItem(this.state.currentToDoItem)}>
              <p>Add Item</p>
          </button>
          <p>{this.state.currentToDoItem}</p>
          <div>
              <p>To Do Items</p>
              {
                this.state.toDoList.map((item, index) =>
                  <p onClick={ () => this.handleClick(index) } className={ item.isComplete ? 'completed' : '' } key={index}>{item.value} </p>)
              }
          </div>
      </div>
    );
  }
}

ReactDOM.render( < App / > , document.querySelector("#app"))
body {
  background: #20262E;
  padding: 20px;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}

.completed {
  text-decoration: line-through;
}
<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="app"></div>

更新:为现代代码方法创建了 TODO fiddler code using React Hooks

const initialState = {
  items: [
    { text: "Learn JavaScript", done: false },
    { text: "Learn React", done: false },
    { text: "Play around in JSFiddle", done: true },
    { text: "Build something awesome", done: true }
  ]
};

function appReducer(state, action) {
  switch (action.type) {
    case 'ITEM_STATUS_CHANGE':{
       let affected = state.items.slice();
       affected[action.index].done = !affected[action.index].done;
       return Object.assign({}, state,  { items: affected });
    }

    case 'ADD_ITEM_TO_LIST':{
       let affected = state.items.slice();
       affected.push({ text: action.data, done : false})   
       return Object.assign({}, state,  { items: affected });
    }

    default:
      throw new Error();
  }
}

function TodoApp(props){
    const [state, dispatch] = React.useReducer(appReducer, initialState);

    return (
      <div>
        <h2>Todos: 
          <input type="text" id="todoTextItem"/>
          <button 
          onClick={()=>{
                dispatch({
                type: 'ADD_ITEM_TO_LIST',
                data: window.todoTextItem.value
              })
          }}
          >Add Item</button>
        </h2>
        <ol>
        {state.items.map((item, index) => (
          <li key={index}>
            <label>
              <input 
                type="checkbox"
                checked={item.done}
                onChange={()=>{
                    dispatch({
                    type: 'ITEM_STATUS_CHANGE',
                    index: index,
                  })
                }}
              /> 
              <span className={item.done ? "done" : ""}>{item.text}</span>
            </label>
          </li>
        ))}
        </ol>
      </div>
    );
}

ReactDOM.render(<TodoApp />, document.querySelector("#app"))

并在 CSS

body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}

li {
  margin: 8px 0;
}

h2 {
  font-weight: bold;
  margin-bottom: 15px;
}

.done {
  color: rgba(0, 0, 0, 0.3);
  text-decoration: line-through;
}

input {
  margin-right: 5px;
}

解释:

基本上我正在创建一个带有完成布尔标志的列表,默认情况下为 false,这有助于确定添加到列表中的 TODO 项目是否已完成或未使用 reducers。使用该逻辑 class .done 被切换。 您可以根据需要更改代码,在设置状态时将 TODO 列表与已完成列表项分开

This is a Unit testable code by creating Jest snapshot. Never to manipulate DOM directly, which will defeat the purpose of React's snapshot testing.


fiddle code 使用 Class 组件.

使用它来比较和学习基于 class 的现代钩子概念。