onblur和onlick

来源:互联网 发布:淘宝店铺复古港风推荐 编辑:程序博客网 时间:2024/05/22 13:19

有这样的一个需求:

这里写图片描述

  1. 点击“更改”,出现右侧菜单,点击选项后对“更改”左侧的结果进行更改,更改成功后菜单消失
  2. 菜单出现的情况,点击空白菜单消失

应该是一个很普遍的需求,但是在react里实现还是花费了我一些力气,实际上和react的关系不太,还是各个事件的发生的顺序

首先为了实现点击按钮出现,点击空白消失,对更改按钮的span增加了tabindex,这样就可以通过onfocus和onblur实现,html布局要点就是右侧菜单div用absolute定位,是“更改”的span的子元素,这样点击菜单进行更改时就不会触发span的blur时间,点击完成后再绑定隐藏菜单的事件,perfect!来试一下:

部分代码:

// 点击显示更改学生自判答案的菜单  @action showSelect(index) {    for (let i = 0; i < this.selectShow.length; i++) {      this.selectShow[i] = false    }    this.selectShow[index] = true;  }  // 点击隐藏更改学生自判答案的菜单  @action hideSelect(index) {    this.selectShow[index] = false;  }  // 点击更改学生自判答案  @action onClickChangeScore(index, e) {    const {markStore} = this.props;    const {questions} = markStore;    let currentQuestion = questions[index];    currentQuestion.score = Number(e.target.value);    // 强制MarkScoreTable组件刷新    this.updateCounter += 1;    // 更改答对率    markStore.changeAccuracy(questions);    // 隐藏当前选择菜单    this.selectShow[index] = false;  }<div className={styles.markSelectWrap}>    <span>学生自判:</span>    <i className={styles.myAnswerResultIcon} name={question.score}/>    <span className={styles.changeScore} tabIndex="1" onFocus={this.showSelect.bind(this, question.number)} onBlur={this.hideSelect.bind(this, question.number)}>更改        <div className={styles.markSelect} style={{'display': this.selectShow[question.number] ? 'flex' : 'none'}}>            <div className={styles.markSelectLeft}>                <div className={styles.selectLeftContent}/></div>            <div className={styles.markSelectRight}>                <div className={styles.selectRight}><input name="select" type="radio" value="2" onClick={this.onClickChangeScore.bind(this, question.number)}/></div>                <div className={styles.selectHalf}><input name="select" type="radio" value="1" onClick={this.onClickChangeScore.bind(this, question.number)}/></div>                <div className={styles.selectWrong}><input name="select" type="radio" value="0" onClick={this.onClickChangeScore.bind(this, question.number)}/></div>            </div>        </div>    </span></div>

很完美,在我们的客户端和chrome浏览器都实现了,(我们的客户端是用cef框架的chrome46内核的应用程序),但是事情没有到此结束……

程序发布后,把自己的chrome由原来的46升级到了最新的52,发现点击后无法更改答案了!!!降级到49也是不行,只有在46是可以的,为什么?

不知道chrome在46升级后发生什么改变,是修复了bug还是又产生了bug(我估计是前者,之前的实现应该是利用了低版本chrome的bug),虽然对客户端没有影响,但是还是应该解决它。

分析原因,就是在新版本的浏览器中,浏览器并不认为点击出现的菜单属于“更改”的span,点击时先发生了blur事件,所以click事件根本没有发生,上网查找了资料,遇到这种情况,一种解决方法就是用mousedown事件来代替click事件,原因知乎上的邹鹏分析的很好,总结一下:

click事件的触发条件:鼠标点下去,然后松开。点击菜单时本想先触发click,结果先触发了blur,等到松开鼠标真正触发click的时候,鼠标已经不在被绑定click的元素上,所以无法触发。

显然,事件的顺序是:

mousedown -> blur -> mouseup(click)

所以对上面的代码进行更改,1是将input的click事件更改为mousedown事件,而是将事件里的隐藏菜单的代码去掉,由blur事件完成菜单的隐藏

更改后的部分代码如下:

// 点击显示更改学生自判答案的菜单  @action showSelect(index) {    for (let i = 0; i < this.selectShow.length; i++) {      this.selectShow[i] = false    }    this.selectShow[index] = true;  }  // 点击隐藏更改学生自判答案的菜单  @action hideSelect(index) {    this.selectShow[index] = false;  }  // 点击更改学生自判答案  @action onClickChangeScore(index, e) {    const {markStore} = this.props;    const {questions} = markStore;    let currentQuestion = questions[index];    currentQuestion.score = Number(e.target.value);    // 强制MarkScoreTable组件刷新    this.updateCounter += 1;    // 更改答对率    markStore.changeAccuracy(questions);    // 隐藏当前选择菜单    // this.selectShow[index] = false;  }<div className={styles.markSelectWrap}>    <span>学生自判:</span>    <i className={styles.myAnswerResultIcon} name={question.score}/>    <span className={styles.changeScore} tabIndex="1" onFocus={this.showSelect.bind(this, question.number)} onBlur={this.hideSelect.bind(this, question.number)}>更改        <div className={styles.markSelect} style={{'display': this.selectShow[question.number] ? 'flex' : 'none'}}>            <div className={styles.markSelectLeft}>                <div className={styles.selectLeftContent}/></div>            <div className={styles.markSelectRight}>                <div className={styles.selectRight}><input name="select" type="radio" value="2" D={this.onClickChangeScore.bind(this, question.number)}/></div>                <div className={styles.selectHalf}><input name="select" type="radio" value="1" onMouseDown={this.onClickChangeScore.bind(this, question.number)}/></div>                <div className={styles.selectWrong}><input name="select" type="radio" value="0" onMouseDown={this.onClickChangeScore.bind(this, question.number)}/></div>            </div>        </div>    </span></div>

但是这样的话好像在低版本的上也会有问题,点击后不消失,我也是醉了。

以后如果做这种不是针对特性版本浏览器客户端的,不行就用透明度去实现,或者在document上绑定事件,然后判断target去实现

原创粉丝点击