当前位置:首页 > 系统运维

React + TypeScript:如何处理常见事件?

大家好,处理常我是事件CUGGZ。之前分享过一篇《如何优雅地在 React 中使用TypeScript,处理常看这一篇就够了!》,事件文中介绍了React和TypeScript搭配使用的处理常一些常见用法。其中第四部分介绍了在React的事件事件处理中如何定义事件类型,下面来通过一些简单的处理常 Demo (每个 Demo 后面都有 CodeSandBox 的在线体验地址)看看如何在 React + TypeScrip 中处理常见的事件!

目录:onClickonChangeonScrollonSubmitonCopy、onCut、事件onPasteonMouseOver、处理常onMouseOutonLoad、事件onErroronkeydown、处理常onkeypress、事件onkeyuponFocus、处理常onBluronDragStart、事件onDrop、处理常onDragOverwindow.resize

1、 onClick

onClick 是用的最多的事件之一,这里主要列举两种类型的 onClick 事件:

button按钮的onClick事件。任意元素的的onClick事件。

下面先来看看按钮的 onClick 事件,云服务器提供商当点击按钮时,在页面显示按钮的名称:

import React, { useState } from "react";

import "./styles.css";

const App: React.FunctionComponent = () => {

const [clickedButton, setClickedButton] = useState("");

const buttonHandler = (event: React.MouseEvent) => {

event.preventDefault();

const button: HTMLButtonElement = event.currentTarget;

setClickedButton(button.name);

};

return (

Button 1

Button 2

Button 3

{ clickedButton !== "" ? `点击了 ${ clickedButton}` : "没有点击任何按钮"}

);

};

export default App;

可以看到,onClick 事件的事件处理对象的类型都定义为了 MouseEvent,其中传入的参数为绑定事件的元素的类型。可以通过事件对象的 currentTarget 属性来获取点击元素的属性。

在线体验:https://codesandbox.io/s/dawn-feather-8gofq1。

再来看看任意元素的 onClick事件,点击一个元素时,在控制台打印点击元素的类型、长度、宽度:

import React from "react";

import "./styles.css";

const App: React.FunctionComponent = () => {

// 当 container 被点击时,触发该事件

const divClickedHandler = (event: React.MouseEvent) => {

const div = event.currentTarget;

console.log(

"ElementName: ", div.tagName,

"Width: ", div.clientWidth,

"Height: ", div.clientHeight

);

};

// 当 h1 被点击时,触发该事件

const headingClickedHandler = (event: React.MouseEvent) => {

event.stopPropagation();

const heading = event.currentTarget;

console.log(

"ElementName: ", heading.tagName,

"Width: ", heading.clientWidth,

"Height: ", heading.clientHeight

);

};

// 当图片被点击时,触发该事件

const imgClickedHandler = (event: React.MouseEvent) => {

event.stopPropagation();

const img = event.currentTarget;

console.log(

"ElementName: ", img.tagName,

"Width: ", img.clientWidth,

"Height: ", img.clientHeight

);

};

return (

Hello World

src="https://resource-1255585089.cos.ap-beijing.myqcloud.com/111.png"

alt="111"

onClick={ imgClickedHandler}

/>

);

};

export default App;

可以看到,onClick 事件的事件处理对象的类型都定义为了 MouseEvent,其中传入的参数为绑定事件的元素的类型。需要注意,在任意元素上添加点击事件时,站群服务器会触发事件冒泡,比如上面的例子,当点击是图片或者h1标签时就会导致其父元素div的点击事件触发。可以使用下面的代码来避免默认事件:

event.stopPropagation();

在线体验:https://codesandbox.io/s/serverless-glade-g41upi。

2、 onChange

下面来看看 onChange 事件,先来看 select 元素的 onChange 事件的例子,当选中元素时,选中元素的值会显示在页面上:

import React, { useState } from "react";

import "./styles.css";

const App: React.FunctionComponent = () => {

const [selectedOption, setSelectedOption] = useState();

const selectChange = (event: React.ChangeEvent) => {

const value = event.target.value;

setSelectedOption(value);

};

return (

选择一个

{ selectedOption &&

{ selectedOption}

}

);

};

export default App;

可以看到,select 元素的 onSelect 的事件对象类型为 ChangeEvent,传入的参数为 select 元素的类型。可以通过 target 属性来获取 select选中的值。

在线体验:https://codesandbox.io/s/frosty-lichterman-33fpky。

input 元素的 onChange 事件的例子,在输入框中输入内容,点击搜索按钮,在页面显示搜索结果:

import React, { useState } from "react";

import "./styles.css";

interface Item {

id: number;

name: string;

price: number;

}

const PRODUCTS: Item[] = [

{

id: 1,

name: "Apple",

price: 1

},

{

id: 2,

name: "Book",

price: 5

},

{

id: 3,

name: "Banana",

price: 0.5

},

{

id: 4,

name: "Table",

price: 200

}

];

const App: React.FunctionComponent = () => {

const [query, setQuery] = useState("");

const [result, setResult] = useState();

// 当 input 的内容改变时触发

const inputHandler = (event: React.ChangeEvent) => {

const enteredName = event.target.value;

setQuery(enteredName);

};

// 点击搜索时触发

const search = () => {

const foundItems = PRODUCTS.filter((item) =>

item.name.toLowerCase().includes(query.toLowerCase())

);

setResult(foundItems);

};

return (

value={ query}

onChange={ inputHandler}

placeholder="输入要搜索的商品名称"

className="input"

/>

{ result && result.length > 0 ? (

result.map((item) => (

{ item.id}

{ item.name}

{ item.price}¥

))

) : (

没有找到!亿华云计算

)}

);

};

export default App;

可以看到,这里input 的事件处理对象的类型为 ChangeEvent。要想获取输入的值需要从事件对象的 target 属性中获取。

在线体验:https://codesandbox.io/s/pedantic-murdock-lejmg6。

3、 onScroll

onScroll 事件在元素的滚动条被滚动时触发。

下面来看一个例子,当元素发生滚动时,计算滚动了多少的元素,从而计算页面滚动进度的百分比值,并显示在页面上:

import React, { useState } from "react";

import "./styles.css";

const DUMMY_DATA = Array.from({ length: 100 }, (x, i) => {

return {

id: i,

title: `Item ${ i}`

};

});

const App: React.FunctionComponent = () => {

const [progress, setProgress] = useState(0);

// 当元素发生滚动时触发该事件

const scrollHandler = (event: React.UIEvent) => {

const containerHeight = event.currentTarget.clientHeight;

const scrollHeight = event.currentTarget.scrollHeight;

const scrollTop = event.currentTarget.scrollTop;

setProgress(((scrollTop + containerHeight) / scrollHeight) * 100);

};

return (

<>

{ DUMMY_DATA.map((item) => (

{ item.title}

))}

{ progress.toFixed(2)}%

);

};

export default App;

可以看到,onScroll 事件的事件对象类型定义为了:React.UIEvent,参数为绑定事件的元素的类型。可以通过事件对象的 currentTarget 属性来获取页面滚动的相关值。

在线体验:https://codesandbox.io/s/competent-hellman-qh7non。

4、 onSubmit

下面来看看表单的 onSubmit 事件,该事件在表单提交时触发:

import React, { useState } from "react";

import "./styles.css";

const App: React.FunctionComponent = () => {

const [term, setTerm] = useState("");

const submitForm = (event: React.FormEvent) => {

// 防止页面重新加载

event.preventDefault();

alert(term);

};

return (

value={ term}

onChange={ (e) => setTerm(e.target.value)}

type="text"

className="input"

/>

提交

);

};

export default App;

表单提交事件的时间对象类型为 FormEvent。需要注意,为了防止页面在表单的 onSubmit事件触发时重新加载,需要调用:

event.preventDefault();

在线体验:https://codesandbox.io/s/condescending-danny-e1eerd。

5、 onCopy、onCut、onPaste

下面来看看常见的复制、剪切、粘贴这三个时间:

onCopy:在用户复制元素或元素的内容(如文本、图像)时触发。onPaste:在用户在元素中粘贴一些内容时触发。onCut:在用户剪切元素的内容时发生,此事件主要用于 input (`type=”text”``) 和 textarea 元素。

下面来看一个例子,当进行复制、剪切、粘贴时,给操作的元素加上一些样式:

import React, { useState } from "react";

import "./styles.css";

const App: React.FunctionComponent = () => {

const [text, setText] = useState("hello world");

// 复制:onCopy

const copyHandler = (event: React.ClipboardEvent) => {

event.currentTarget.style.border = "3px solid green";

};

// 剪切:onCut

const cutHandler = (event: React.ClipboardEvent) => {

event.currentTarget.style.border = "3px solid orange";

event.currentTarget.style.backgroundColor = "yellow";

event.currentTarget.disabled = true;

setText("内容被剪切啦");

};

// 粘贴:onPaste

const pasteHandler = (event: React.ClipboardEvent) => {

event.currentTarget.style.border = "5px solid purple";

event.currentTarget.style.backgroundColor = "orange";

event.currentTarget.value = event.clipboardData.getData("text").toUpperCase();

event.preventDefault();

};

return (

在下方粘贴:

);

};

export default App;

可以看到,这三个事件的事件处理对象的类型都定义为了 ClipboardEvent,其中传入的参数为绑定事件的元素的类型。可以通过 currentTarget 属性来获取事件对象的属性。

在线体验:https://codesandbox.io/s/sleepy-keldysh-w5vemj。

6、 onMouseOver、onMouseOut

onmouseover 和 onmouseout 是常用的两个鼠标事件:

onmouseover:在鼠标指针移动到指定的对象上时触发。onmouseout:在鼠标指针移出指定的对象时触发。

下面来看一个例子,当鼠标在元素上和移出元素时给元素添加不同的样式:

import React from "react";

import "./styles.css";

const App: React.FunctionComponent = () => {

// 当鼠标指针位于box上时,将触发此功能

const boxMouseOverHandler = (event: React.MouseEvent) => {

const box: HTMLDivElement = event.currentTarget;

box.style.backgroundColor = "lightblue";

};

// 当鼠标指针移出box时,将触发此功能

const boxMouseOutHandler = (event: React.MouseEvent) => {

const box: HTMLDivElement = event.currentTarget;

box.style.backgroundColor = "lightgreen";

};

// 当鼠标指针位于输入框上时,将触发此功能

const inputMouseOverHandler = (event: React.MouseEvent) => {

const input: HTMLInputElement = event.currentTarget;

input.style.backgroundColor = "lime";

};

//当鼠标指针移出输入框时,将触发此功能

const inputMouseOutHandler = (event: React.MouseEvent) => {

const input: HTMLInputElement = event.currentTarget;

input.style.backgroundColor = "white";

};

//当鼠标指针位于按钮上时,将触发此功能

const buttonMouseOverHandler = (event: React.MouseEvent) => {

const btn: HTMLButtonElement = event.currentTarget;

btn.style.border = "3px solid red";

btn.style.backgroundColor = "orange";

};

// 当鼠标指针移出按钮时,将触发此功能

const buttonMouseOutHandler = (event: React.MouseEvent) => {

const btn: HTMLButtonElement = event.currentTarget;

btn.style.border = "none";

btn.style.backgroundColor = "yellow";

};

return (

className="box"

onMouseOver={ boxMouseOverHandler}

onMouseOut={ boxMouseOutHandler}

>

onMouseOver={ inputMouseOverHandler}

onMouseOut={ inputMouseOutHandler}

placeholder="hello world"

/>

onMouseOver={ buttonMouseOverHandler}

onMouseOut={ buttonMouseOutHandler}

>

Button

);

};

export default App;

可以看到,这两个事件的事件处理对象的类型都定义为了 MouseEvent,其中传入的参数为绑定事件的元素的类型。可以通过事件对象的 currentTarget 来获取事件对象的属性。

在线体验:https://codesandbox.io/s/nervous-cloud-5r6d6p。

7、 onLoad、onError

onLoad 和 onError 是页面外部资源加载相关的两个相关事件:

onload:资源加载失败。onerror:资源加载出错。

下面来看一个例子, 当图片成功时给它添加类名 success,加载失败时添加类型 error,并更换为备用图片的URL:

import React from "react";

import "./styles.css";

const IMAGE ="https://resource-1255585089.cos.ap-beijing.myqcloud.com/111.png";

const FALLBACK_IMAGE ="https://resource-1255585089.cos.ap-beijing.myqcloud.com/222.png";

const App: React.FunctionComponent = () => {

const imageOnLoadHandler = (event: React.SyntheticEvent) => {

// 图片加载成功时,打印图片的地址,并添加类名 success

console.log(event.currentTarget.src);

if (event.currentTarget.className !== "error") {

event.currentTarget.className = "success";

}

};

const imageOnErrorHandler = (event: React.SyntheticEvent) => {

// 图片加载失败时,加载替代的图片,并添加类名 error

event.currentTarget.src = FALLBACK_IMAGE;

event.currentTarget.className = "error";

};

return (

src={ IMAGE}

onLoad={ imageOnLoadHandler}

onError={ imageOnErrorHandler}

alt="111"

/>

);

};

export default App;

可以看到,这两个事件的事件处理对象的类型都定义为了 SyntheticEvent,其中传入的第一个参数为绑定事件的元素的类型。可以通过事件对象的 currentTarget 属性来获取事件对象的属性。

在线体验:https://codesandbox.io/s/determined-tamas-rjwjoq。

8、 onkeydown、onkeypress、onkeyup

下面来看几个常见的键盘事件:

onKeyDown:在用户按下一个键盘按键时触发。onKeyUp:在键盘按键被松开时触发。onKeyPress:在键盘按键被按下并释放一个键时发生。在所有浏览器中 onkeypress 事件只能监听字母和数字,不能监听一些特殊按键(ALT、CTRL、SHIFT、ESC、箭头等)。监听一个用户是否按下按键请使用 onkeydown 事件,所有浏览器都支持 onkeydown 事件。

这三个事件的执行顺序如下:

onkeydownonkeypressonkeyup

来看一个例子,按下ESC键可以清除已经输入的文本,按下Enter键可以弹出已经输入的文本:

import React, { useState } from "react";

import "./styles.css";

const App: React.FunctionComponent = () => {

const [enteredText, setEnteredText] = useState("");

// onKeyDown 事件处理函数

const keyDownHandler = (event: React.KeyboardEvent) => {

if (event.code === "Enter") {

alert(`输入内容:"${ enteredText}"`);

}

};

// onKeyUp 事件处理函数

const keyUpHandler = (event: React.KeyboardEvent) => {

if (event.code === "Escape") {

const confirm = window.confirm("确定清除文本吗?");

if (confirm) {

setEnteredText("");

}

}

};

// onKeyPress 事件处理函数

const keyPressHandler = (event: React.KeyboardEvent) => {

//...

};

return (

onKeyDown={ keyDownHandler}

onKeyUp={ keyUpHandler}

onKeyPress={ keyPressHandler}

type="text"

className="text-input"

value={ enteredText}

onChange={ (e) => setEnteredText(e.target.value)}

/>

);

};

export default App;

这三个事件的事件对象类型都是 KeyboardEvent。可以通过事件对象的 code属性获取按下的键盘键值。

在线体验:https://codesandbox.io/s/prod-sky-txwzgd。

再来看一个简单的例子,通过在键盘上按下上下左右键使得盒子在页面上移动:

import React, { useState } from "react";

import "./styles.css";

const App: React.FunctionComponent = () => {

const [left, setLeft] = useState(0);

const [top, setTop] = useState(0);

// onKeyDown 事件处理函数

const keyDownHandler = (event: React.KeyboardEvent) => {

console.log(event.code);

if (event.code === "ArrowUp") {

setTop((top) => top - 10);

}

if (event.code === "ArrowDown") {

setTop((top) => top + 10);

}

if (event.code === "ArrowLeft") {

setLeft((left) => left - 10);

}

if (event.code === "ArrowRight") {

setLeft((left) => left + 10);

}

};

return (

);

};

export default App;

在线体验:https://codesandbox.io/s/hungry-meninsky-zhkbzb。

9、 onFocus、onBlur

onfocus:在元素获得焦点时触发,适用于、 以及标签。 onblur:在元素失去焦点时触发,常用于表单验证。

下面来看一个例子,在输入框中输入内容,输入过程中保存输入的值, 当输入完成,失去输入焦点时,对输入内容进行校验:

import React, { useState } from "react";

import "./styles.css";

const App: React.FunctionComponent = () => {

const [name, setName] = useState("");

const [isValid, setIsValid] = useState(false);

const [isFocus, setIsFocus] = useState(false);

const [isBlur, setIsBlur] = useState(false);

// 处理 input 的 onChange事件

const changeHandler = (event: React.ChangeEvent) => {

setName(event.target.value);

};

// 处理 input 的 onFocus 事件

const focusHandler = (event: React.FocusEvent) => {

setIsFocus(true);

setIsBlur(false);

console.log(event);

};

// 处理 input 的 onBlur 事件

const blurHandler = (event: React.FocusEvent) => {

setIsFocus(false);

setIsBlur(true);

if (name.match(/^[a-z][a-z\s]*$/i)) {

setIsValid(true);

} else {

setIsValid(false);

}

console.log(event);

};

return (

type="text"

onFocus={ focusHandler}

onBlur={ blurHandler}

value={ name}

onChange={ changeHandler}

className="input"

placeholder="请输入名字"

/>

{ isFocus && 只能输入字母和空格}

{ isBlur && !isValid &&

输入格式错误

}

{ isBlur && isValid &&

输入正确

}

);

};

export default App;

这里两个事件的事件对象类型都是 FocusEvent,传入的参数是 input 元素的类型。

在线体验:https://codesandbox.io/s/spring-moon-roegc5。

10、 onDragStart、onDrop、onDragOver

拖拽操作在HTML5 是作为标准的一部分。能够使用HTML5所支持的事件和属性来实现拖拽操作。下面是三个常用的拖拽事件:

onDragStart:开始拖拽时触发,事件里利用dataTransfer保存拖拽元素的 class 或 id。onDrop:元素放置时不断触发,事件里利用dataTransfer来获取所保存的数据,并进行业务处理。onDragOver:

在拖拽时不断触发,在其中取消默认行为可以保证该标签可以放置拖拽元素。import React, { useState } from "react";

import "./styles.css";

const PHOTO_URL = "https://resource-1255585089.cos.ap-beijing.myqcloud.com/111.png";

const App: React.FunctionComponent = () => {

const [content, setContent] = useState("Drop Something Here");

// 开始拖拽时触发改事件

const dragStartHandler = (event: React.DragEvent, data: string) => {

event.dataTransfer.setData("text", data);

};

// 在放置时触发该事件

const dropHandler = (event: React.DragEvent) => {

event.preventDefault();

const data = event.dataTransfer.getData("text");

setContent(data);

};

// 使得第三个盒子可以放下

const allowDrop = (event: React.DragEvent) => {

event.preventDefault();

};

return (

className="box1"

onDragStart={ (event) => dragStartHandler(event, PHOTO_URL)}

draggable={ true}

>

111

className="box2"

onDragStart={ (event) => dragStartHandler(event, "黄色卡片")}

draggable={ true}

>

{ content.endsWith(".png") ? (

) : (

{ content}

)}

);

};

export default App;

可以看到,两个拖拽事件的事件对象类型都是 DragEvent。可以通过事件对象的 dataTransfer 来获取事件对象的属性。

在线体验:https://codesandbox.io/s/crazy-cloud-5jejr1。

11、window.resize

在 React 中是不支持直接定义 onResize 事件的。可以使用浏览器原生支持的 window.resize 事件,当浏览器窗口发生变化时会触发改事件。

可以使用以下两种方式之一来设置事件处理函数:

window.resize = myHandlerFunction;

window.addEventListener(resize, myHandlerFunction);

在 React 中,要在浏览器窗口大小发生变化时重新渲染组件,可以使用 useStatehook 来实现:

useEffect(() => {

window.onresize = myHandlerFunction;

}, []);

useEffect(() => {

window.addEventListener(resize, myHandlerFunction);

}, []);

下面来看一个例子,在改变浏览器窗口的大小时,页面实时显示浏览器窗口的长度和宽度,并在不同宽度时显示不同的背景色:

import React, { useState, useEffect, FunctionComponent } from "react";

import "./styles.css";

interface Size {

width: number;

height: number;

}

const App: FunctionComponent = () => {

const [size, setSize] = useState();

const resizeHanlder = () => {

const width = window.innerWidth;

const height = window.innerHeight;

setSize({

width: width,

height: height,

});

};

useEffect(() => {

window.onresize = resizeHanlder;

}, []);

return (

className="container"

style={ {

backgroundColor:

!size || size.width <= 500

? "white"

: size && size.width <= 700

? "green"

: "orange",

}}

>

{ size && (

<>

Width: { size.width}

Height: { size.height}

)}

);

};

export default App;

在线体验:https://codesandbox.io/s/async-leaf-m62ixj。

12、 备忘录

常见的 Event 事件对象如下:

剪切板事件对象:ClipboardEvent。拖拽事件对象:DragEvent。焦点事件对象:FocusEvent。表单事件对象:FormEvent。Change事件对象:ChangeEvent。键盘事件对象:KeyboardEvent。鼠标事件对象:MouseEvent。触摸事件对象:TouchEvent。滚轮事件对象:WheelEvent。动画事件对象:AnimationEvent。过渡事件对象:TransitionEvent。

常见的元素类型如下:

a: HTMLAnchorElement。body: HTMLBodyElement。br:HTMLBRElement。button:HTMLButtonElement。div:HTMLDivElement。h1:HTMLHeadingElement。h2:HTMLHeadingElement。h3:HTMLHeadingElement。html:HTMLHtmlElement。img:HTMLImageElement。input:HTMLInputElement。ul: HTMLUListElement。li:HTMLLIElement。link:HTMLLinkElement。p:HTMLParagraphElement。span: HTMLSpanElement。style:HTMLStyleElement。table:HTMLTableElement。tbody:HTMLTableSectionElement。video:HTMLVideoElement。audio:HTMLAudioElement。meta:HTMLMetaElement。form:HTMLFormElement。

分享到:

滇ICP备2023006006号-16