简体   繁体   English

通过 onClick 在 React.js 中删除一个段落?

[英]Strikethrough a Paragraph in React.js via onClick?

I'm pretty much ready to rip my hair out.我几乎准备好撕掉我的头发了。 So my final project in my Javascript class is an experimental thing with learning React.js, where you do a basic todo list.所以我在 Javascript 课上的最后一个项目是学习 React.js 的实验性项目,在那里你做一个基本的待办事项列表。 I got all that done and working, and I can have it add things properly.我完成了所有工作并完成了工作,我可以让它正确添加内容。 But my final hurdle is making it so that onclicking the printed paragraph from the button will cause them to give the printed paragraphs the strikethrough property, which can be undone by clicking on it again.但我的最后一个障碍是使点击按钮上的打印段落会导致他们为打印的段落提供删除线属性,可以通过再次单击它来撤消。

I've looked up everywhere, I've tried other examples from here, and nothing I can think of gets the strikethrough to take place.我到处查找,我从这里尝试过其他示例,我想不出任何可以删除删除线的内容。 I tried a basic Javascript function that would do what I wanted if this was an HTML/non-react file, but it breaks the react page when I try to plop it in. So I spent a stupidly long time on a tutorial trying to figure out what to do, and I maybe figured out the step in the right direction?我尝试了一个基本的 Javascript 函数,如果这是一个 HTML/非反应文件,它会做我想做的事情,但是当我尝试插入它时它会破坏反应页面。所以我花了很长时间在教程上试图弄清楚弄清楚该怎么做,我也许找到了朝着正确方向迈出的一步? But I still can't get anything to happen and I don't know how to establish an onclick to this.但我仍然无法让任何事情发生,我不知道如何为此建立一个点击。

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;

This is my App.js code.这是我的 App.js 代码。 As you can see, everything else should work fine, but I have no clue how to add a strikethrough effect to what would result from the this.state.toDoList.map((item, index) => <p key={index}>{item} </p>) bit like I would with a function in normal javascript.如您所见,其他一切都应该可以正常工作,但我不知道如何为this.state.toDoList.map((item, index) => <p key={index}>{item} </p>)有点像我使用普通 javascript 中的函数。 How do I make the printed lines strikethrough via onclick, and then how do I undo that by clicking on it again?如何通过 onclick 使打印的线条删除线,然后如何通过再次单击来撤消该操作? (I assume with a second onclick) I really just need to know how to get a working strikethrough with this, as everything else is pretty much working. (我假设第二次点击)我真的只需要知道如何通过这个获得有效的删除线,因为其他一切都非常有效。

One of the most comfortable ways to do that is as advised in comments.正如评论中所建议的那样,最舒适的方法之一是做到这一点。 A really quick way to implement this is to toggle class list.实现这一点的一个非常快速的方法是切换类列表。 In the code bellow, I added a function crossLine which toggles class name "crossed-line" and adds event listener on mapped to-dos (in render function).在下面的代码中,我添加了一个函数crossLine ,它切换类名“crossed-line”并在映射的 to-dos 上添加事件侦听器(在render函数中)。 Then in your App.css add a line然后在你的App.css添加一行

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

Here's your edited component code.这是您编辑的组件代码。

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>
        );
    }
}

As commented, you will have to keep a handle click and add class to add strikethrough using CSS.正如所评论的,您必须保持一个句柄单击并添加类以使用 CSS 添加删除线。

For this I have updated your JSX to:为此,我已将您的 JSX 更新为:

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

and the signature of toDoItem from string to an object:以及toDoItem从字符串到对象的签名:

{
    value: string;
    isComplete: boolean
}

and based on this flag, I'm adding 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>

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

I have modified your code to achieve the required functionality.我已经修改了您的代码以实现所需的功能。 This code does exactly what you want.此代码完全符合您的要求。

Update : Created a TODO fiddler code using React Hooks for modern code approach.更新:使用React Hooks为现代代码方法创建了一个TODO fiddler代码。

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"))

and in CSS并在 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;
}

Explanation:解释:

Basically i am creating a list with done boolean flag which is false by default, which helps to identify if the TODO items added to the list is finished or not using reducers .基本上我正在创建一个带有 done 布尔标志的列表,默认情况下它是false ,这有助于确定添加到列表中的 TODO 项目是否已完成或未使用reducers With that logic class .done is toggled.使用该逻辑类.done被切换。 You can change the code according to your need by segregating TODO list from done list items while setting state您可以通过在设置状态时将待办事项列表与完成列表项分开来根据需要更改代码

This is a Unit testable code by creating Jest snapshot.这是通过创建 Jest 快照的单元可测试代码。 Never to manipulate DOM directly, which will defeat the purpose of React's snapshot testing.永远不要直接操作 DOM,这会违背 React 快照测试的目的。


Old fiddle code using Class Component .使用Class Component 的小提琴代码

Use this to compare and learn modern hooks concepts from class based.使用它来比较和学习基于类的现代钩子概念。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM