上节课我们介绍了如何添加新的todo,而我们的功能实现的也挺多的了。但是离我们完整的需求还远得很呢,我们既然有了添加功能,那么自然要有删除功能。但是我们的需求中一直都是将删除按钮隐藏的。而且我们是要求鼠标移入时才显示,那么这节课我们来学习如何添加这个功能。

回顾

在开始这节课的内容之前我们先来对上节课的内容来做一个简单的回顾。

  • 添加todo分为 5 步
  • 输入todo
  • 按下回车键
  • 获取到输入的值
  • 添加到App组件的state
  • 重新加载页面
  • 通过onKeyUp来监听键盘事件
  • 通过keyCode来判断是否是回车键
  • 通过父组件传入子组件一个函数来提供一个修改父组件state的入口给子组件

以上便是上节课的主要知识点,接下来开始添加我们的新功能来实现鼠标移入效果

最终效果

我们来回想一下我需要什么效果?首先我们鼠标移动到每条todo上面的时候要求todo高亮,其实就只是修改一下背景色而已。其次,当我们鼠标移入的时候氩气在todo右侧显示出删除按钮。

实现

既然我们已经知道了我们要的效果,那么我们来分析一下这么实现吧:

首先理性分析一下,有没有可能鼠标同时出现在两条todo之上呢?是不是不可能的?而且我们如果在todo列表中拖动鼠标,是不是要让我们鼠标触碰的todo按顺序依次高亮,一旦鼠标离开马上就取消高亮?那么好,我们是不是将这些todo都分别天剑鼠标移入事件和移出事件就好了?

那么我们分析一下怎么实现?既然我们要在每条todo都加移入移出事件,那么是不是要在Item组件上添加?因为我们在List组件中是遍历了App组件的state然后嵌入了Item组件,那么我们不可能说在遍历的时候添加啊,那只有在Item组件中添加才最合理也最方便,那么我们来修改Item组件:

export default class Item extends Component {
  render() {
    const {todo} = this.props;
    return (
      <li onMouseEnter={this.handleMouse(true)} onMouseLeave={this.handleMouse(false)}>
        ...
      </li>
    )
  }
  handleMouse = flag => {
    return () => {
      console.log(flag);
    };
  };
}

我们来看这段代码,我们给<li>加了两个事件,onMouseEnteronMouseLeave。从名字上面可以看出就是鼠标进入事件和鼠标离开事件。而且我们给这两个事件绑定的都是handleMouse方法。而且还穿了参数。通过truefalse来让方法来判断是移入还是移出。

那么我们光这么写可以吗?我们是不是还要定义方法啊?那么好,来看handleMouse方法。首先我们要接收传入的参数,但是还记不记得我们说过,事件绑定,都要保证绑定的是一个函数,那么也就意味着我们handleMouse方法就要返回一个函数了。然后我们现在返回的函数中来打印一下我们传入的flag看看效果,是不是和我们预期一样鼠标移入打印true,移出打印false

iShot2022-01-08 20.45.38

正如我们预期的效果一样,既然我们已经完成了移入移出来触发效果,那么我们再来分析,鼠标移入,我们要使页面出现变化。可能有人要说了,不对啊,我们这数据也没变啊。样式变了,而且有新元素显示是不是也算是更新了页面呢?所以说,我们是不是可以把移入移出传入的flag存放在state中,然后在鼠标移动时修改state来驱动页面更新?那么另外我们初始化的state应该是什么样子呢?我们再来分析一下,初始状态和鼠标移出使得状态一致,那么初始化的state是不是就应该和鼠标移出一致,直接使用false。那么好,我们来修改一下Item:

export default class Item extends Component {
state = {mouse: false};

  render() {...}
  handleMouse = flag => {
    return () => {
      this.setState({mouse: flag});
    };
  };
}

我们来看一下,我们设置了一个mouse属性,初始化是false。当我们鼠标移入时那么直接setStatestate的值设为flag就可以了。那么我们已经可以修改state了,那么是不是可以通过state来修改Itemstyle

export default class Item extends Component {
state = {mouse: false};

  render() {
    const {todo} = this.props;
    const {mouse} = this.state;
    return (
      <li 
        style={{backgroundColor: mouse ? "#ddd" : "white"}} 
        onMouseEnter={this.handleMouse(true)} onMouseLeave={this.handleMouse(false)}>
        ...
      </li>
    )
  }
  handleMouse = flag => {...};
}

看一下,我们先是解构赋值,来从state中拿到mouse属性,然后在<li>中添加style属性。但是我们是不是不能把style写死啊?而且我们是移入高亮移出就取消高亮,那么什么就用mouse来做个判断就好了,所以我们来看一下效果:

iShot2022-01-08 21.14.55

现在我们实现了高亮了,但是删除按钮还没有显示。我们来看看我们预期的结果是高亮的同时显示删除按钮,那么是不是也可以通过mouse来实现,但是怎么实现呢?我们来看为什么会隐藏?我们是不是给<button>加了一个display属性啊?但是现在我们加了鼠标移入移出事件,是不是就不能把display像原来那样写死为none了?那么我们是不是也用mouse来判断一下就行了?好,我们来修改一下代码

export default class Item extends Component {
  state = { mouse: false };

  render() {
    const { todo } = this.props;
    const { mouse } = this.state;
    return (
      <li ...>
        ...
        <button className="btn btn-danger" style={{ display: mouse ? "block" : "none" }}>删除</button>
      </li>
    )
  }
  handleMouse = flag => {...};
}

来看一下代码,我们用mouse来判断,如果是true,那么我们就显示,否则还是隐藏,现在再看一下结果:

iShot2022-01-08 21.23.49

这一次我们便可以使得鼠标移入则高亮且显示删除按钮。

总结

这节课没有什么特殊的知识点,都是过去的知识

  • 事件绑定必须是函数
  • 通过state驱动页面样式修改

Copyright statement:The articles of this site are all original if there is no special explanation, indicate the source please when you reprint.

Link of this article:https://work.lynchow.com/article/pointer_hover/