第五篇讲组件和组件通信的时候使用过点击事件,在日常开发中我们会用到各种各样的事件,总不能我们只写纯静态页面吧,如果那样为什么我们不直接一个img把设计图放上去呢。咳咳。
本篇主要讲Vue和React的事件和事件对象。从此以后,用户就可以与我们的页面进行交互了。
一、React中的事件
了解React之前,我们需要了解什么是事件。事件是用户在某种事物上的某种行为操作,ok,很好,成功把事件扩充到了这么多字。简单的来说用户的鼠标移动、点击,键盘按下、抬起等都是事件。
有些细心地童靴可能已经发现,React中事件的绑定书写方式与原生JS一样,都是直接onClick,所以React的事件就与JS原生一样吗?当然~不一样,React并不是将 click事件直接绑定在 dom 上面,而是采用事件冒泡的形式,一路冒到 document 上面,这个思路借鉴事件委托机制。这个有机会后边再讲。
1、实现一个简单的事件
我们先简单的写一个事件让大家感受一下,下面我举个栗子。
import React, { Component } from 'react'
export default class Home extends Component {
constructor() {
super()
this.state = {
msg:'我是按钮,我被点了'
}
}
buttonClick(){
console.log(this.state.msg)
}
render() {
return (
<div>
<div>Home</div>
<button onClick={this.buttonClick}>按钮</button>
</div>
)
}
}
在之前说过React组件有两种,有状态和无状态,无状态因为没有state一般用于静态展示,所以在这个例子中我们是用的事状态组件,也就是类组件。函数组件本身就不擅长做交互,没必要难为它...
让我们点击运行一下,诶嘿,报错了
state没找到,怎么会呢,上次说的使用state中的数据就是this.state.属性,我们console一下this看看咋回事(我演的真好)
我们会发现this是undefined,为什么呢?原因是类的方法默认是不绑定this的,说到底还是this指向问题,没有绑定自然就没有了。既然没有,那我们就绑一个!
2.this指向问题解决方法1,bind()
让我们稍加改造一下代码
import React, { Component } from 'react'
export default class Home extends Component {
constructor() {
super()
this.state = {
msg:'我是按钮,我被点了'
}
this.buttonClick = this.buttonClick.bind(this)
}
buttonClick(){
console.log(this.state.msg)
}
render() {
return (
<div>
<div>Home</div>
<button onClick={this.buttonClick}>按钮</button>
</div>
)
}
}
我们也仅仅是在this.state下面增加了一句this.buttonClick = this.buttonClick.bind(this)就解决这个问题,需要注意,这两个buttonClick名字要一样的。
不过这种写法好像不太好看(代码太多,懒),有没有别的方法呢,当然有,往下看。
import React, { Component } from 'react'
export default class Home extends Component {
constructor() {
super()
this.state = {
msg:'我是按钮,我被点了'
}
}
buttonClick(){
console.log(this.state.msg)
}
render() {
return (
<div>
<div>Home</div>
<button onClick={this.buttonClick.bind(this)}>按钮</button>
</div>
)
}
}
这次我们将bind(this)写在了onclick中,也是同样的效果,好像方便了很多,那有没有其他的呢,毕竟又得童靴之前并没有很经常的用bind,还有以下两种方式
3.this指向问题解决方法2,匿名函数+箭头函数
这个方法我们还是在onclick上做手脚,写了一个匿名箭头函数,大家都知道箭头函数是没有this的,它会往上找,所以在这种写法中,this会直接上升到render中,这样他就有this了,也就不会报错了。
import React, { Component } from 'react'
export default class Home extends Component {
constructor() {
super()
this.state = {
msg:'我是按钮,我被点了'
}
}
buttonClick(){
console.log(this.state.msg)
}
render() {
return (
<div>
<div>Home</div>
<button onClick={()=>{this.buttonClick()}}>按钮</button>
</div>
)
}
}
4.this指向问题解决方法3,属性初始化器语法
折腾够了onclick,我们来折腾一下函数本身,这种方法还是实验性的,但是支持的还不错
import React, { Component } from 'react'
export default class Home extends Component {
constructor() {
super()
this.state = {
msg:'我是按钮,我被点了'
}
}
buttonClick = () => {
console.log(this.state.msg)
}
render() {
return (
<div>
<div>Home</div>
<button onClick={this.buttonClick}>按钮</button>
</div>
)
}
}
其实还是利用剪头函数解决这个问题,但是这是实验性的,看好多博主也不是很推荐。
二、React事件对象--event
学过原生JS的肯定不陌生,事件对象event,其实就是事件的各种信息,而且React的事件对象是经过React合成的,没有兼容问题,还是很方便
import React, { Component } from 'react'
export default class Home extends Component {
constructor() {
super()
this.state = {
msg:'我是按钮,我被点了'
}
}
buttonClick(e){
console.log(e)
}
render() {
return (
<div>
<div>Home</div>
<button onClick={(e)=>{this.buttonClick(e)}}>按钮</button>
</div>
)
}
}
事件对象常用的功能就是通过data-*拿取一些数据,或者阻止事件冒泡或默认事件,在React中不能通过return false来阻止默认事件
import React, { Component } from 'react'
export default class Home extends Component {
constructor() {
super()
this.state = {
msg:'我是按钮,我被点了'
}
}
buttonClick(e){
// 阻止默认事件
e.preventDefault();
// 阻止事件冒泡
e.stopPropagation();
}
render() {
return (
<div>
<div>Home</div>
<button onClick={(e)=>{this.buttonClick(e)}}>按钮</button>
</div>
)
}
}
三、Vue中的事件
相对来说Vue的事件更为简单,毕竟使用数据时,并没有React一样遇到报错的情况,this也是很明确的管用了。绑定事件时与React不太相同,但是也是不难理解,v-on:click也可以简写为@click,毕竟谁愿意多敲四次键盘呢。
<template>
<div>
<div>Home</div>
<button v-on:click="buttonClick">按钮</button>
</div>
</template>
<script>
export default {
data() {
return {
msg: '我是vue按钮,我被点击了'
}
},
methods: {
buttonClick() {
console.log(this.msg)
}
}
}
</script>
<style>
</style>
四、Vue事件对象--$event
Vue的事件对象是特殊的,必须写为$event,就算偷懒写event都会报错。不过Vue的事件都自带事件对象,不写$event直接在函数中使用e也不会报错,可以不写但是不能写错。
<template>
<div>
<div>Home</div>
<button v-on:click="buttonClick($event)">按钮</button>
</div>
</template>
<script>
export default {
data() {
return {
msg: '我是vue按钮,我被点击了'
}
},
methods: {
buttonClick(e) {
console.log(e)
}
}
}
</script>
<style>
</style>
既然事件对象是特殊的,有自己的关键字,那么如果我想阻止事件冒泡是不是也可以这么做
<template>
<div @click="boxClick">
<div>Home</div>
<button v-on:click="buttonClick($event)">按钮</button>
</div>
</template>
<script>
export default {
data() {
return {
msg: '我是vue按钮,我被点击了'
}
},
methods: {
buttonClick(e) {
console.log(this.msg)
e.stopPropagation()
},
boxClick() {
console.log('冒泡了')
}
}
}
</script>
<style>
</style>
从结果看很成功,说明$event虽然有那么一丝与众不同,但是基本能做的还是可以做到的。不过在Vue中我们并不经常使用这种方式,因为....(字母太多了)
五、Vue事件修饰符
欢迎来到Vue为我们懒人准备的功能,事件修饰符。还是以上边代码作为例子,我们去阻止冒泡到最外层div。
<template>
<div @click="boxClick">
<div>Home</div>
<button @click.stop="buttonClick($event)">按钮</button>
</div>
</template>
<script>
export default {
data() {
return {
msg: '我是vue按钮,我被点击了'
}
},
methods: {
buttonClick(e) {
console.log(this.msg)
},
boxClick() {
console.log('冒泡了')
}
}
}
</script>
<style>
</style>
灰常简单,只需要在@click后添加一个.stop即可阻止事件冒泡,对于我这种能少敲少背单词就偷懒的人还是很友好的。
除了stop,还有很多常用的修饰符如下
.stop 阻止事件冒泡
.prevent 阻止默认事件
.capture 捕获冒泡,当有冒泡时,会优先触发
.self 事件绑定到自身,只有自身才能触发
.once 事件只触发一次
.native 父组件给子组件绑定一个原生事件,子组件变为一个HTML标签
经常用ElementUI的同学应该常见这个