react 交互_如何在React中建立动画微交互
react 交互
Microinteractions guide a user through your application. They reinforce your user experience and provide delight.
微交互引導(dǎo)用戶(hù)完成您的應(yīng)用程序。 它們可以增強(qiáng)您的用戶(hù)體驗(yàn)并帶來(lái)愉悅感。
You may have seen some of the slick examples of microinteractions on Dribble or CodePen. But do you know how to build your own library of similar UI widgets?
您可能已經(jīng)看到了Dribble或CodePen上的一些微交互示例。 但是,您知道如何構(gòu)建自己的類(lèi)似UI小部件的庫(kù)嗎?
In this article, I’ll focus on animated microinteractions using React, Facebook’s popular, component-oriented UI framework. I’ll build three interactions for a searchbox:
在本文中,我將重點(diǎn)介紹使用Facebook流行的面向組件的UI框架React的動(dòng)畫(huà)微交互。 我將為搜索框構(gòu)建三個(gè)交互:
- open and close the text box 打開(kāi)和關(guān)閉文本框
- move to the top of the screen 移到屏幕頂部
- shake (indicating an error) 搖動(dòng)(指示錯(cuò)誤)
I’ll use a few different implementations:
我將使用一些不同的實(shí)現(xiàn):
CSS transitions
CSS過(guò)渡
react-motion
React運(yùn)動(dòng)
react-animations
React動(dòng)畫(huà)
Here’s a live demo and the code that powers it.
這是一個(gè)現(xiàn)場(chǎng)演示以及支持它的代碼 。
This is one of several posts about Higher Order (HOC) and Stateless Functional Components. The first post is about code reuse in React and React Native, via these techniques.
這是有關(guān)高階(HOC)和無(wú)狀態(tài)功能組件的幾篇文章之一。 第一篇文章是關(guān)于通過(guò)這些技術(shù)在React和React Native中的代碼重用。
什么是微交互? (What is a Microinteraction?)
Dan Saffer (who wrote the book) gives us this definition: “Microinteractions are contained product moments that revolve around a single use case — they have one main task.”
Dan Saffer (寫(xiě)這本書(shū)的人)給了我們這樣的定義 :“微交互包含圍繞一個(gè)用例的產(chǎn)品時(shí)刻,它們具有一項(xiàng)主要任務(wù)。”
Examples might be clearer. Some microinteractions are everywhere, such as a cursor change when hovering over a link or the vibration of your phone when you switch to silent mode. Others, such as an item being added to a shopping cart, aren’t so common (yet).
例子可能更清楚。 到處都有一些微交互,例如,將鼠標(biāo)懸停在鏈接上時(shí)會(huì)更改光標(biāo),或者切換到靜音模式時(shí)手機(jī)會(huì)振動(dòng)。 其他事物(例如,添加到購(gòu)物車(chē)中的商品)并不普遍(尚未)。
我為什么要關(guān)心微交互? (Why should I care about Microinteractions?)
Microinteractions can provide feedback and make your application memorable. When users have so many app choices, better microinteractions might be the clichéd better mousetrap you should build.
微交互可以提供反饋并使您的應(yīng)用程序令人難忘。 當(dāng)用戶(hù)有如此多的應(yīng)用程序選擇時(shí),更好的微交互可能是您應(yīng)該構(gòu)建的老套的更好的捕鼠器。
But I am not a UX designer. So I suggest reading Nick Babich’s post about microinteractions.
但是我不是用戶(hù)體驗(yàn)設(shè)計(jì)師。 因此,我建議閱讀Nick Babich的有關(guān)微交互的文章 。
入門(mén) (Getting Started)
I’ll use create-react-app to bootstrap a React application, but any React setup method will work. Also, I like Material-UI, so I’ll import that too. (This choice is arbitrary — you could use another widget library or manually style your elements.)
我將使用create-react-app引導(dǎo)React應(yīng)用程序,但是任何React設(shè)置方法都可以使用。 另外,我喜歡Material-UI ,所以我也將其導(dǎo)入。 (此選擇是任意的,您可以使用其他小部件庫(kù)或手動(dòng)設(shè)置元素樣式。)
create-react-app search-box-animation cd search-box-animation npm install --save material-ui react-tap-event-plugin組件:一個(gè)簡(jiǎn)單的搜索框 (The Component: a Simple Search Box)
I’ll create a simple search box. It will comprise two elements: a search icon button and a text box. I’ll create a stateless functional component for the search box. (Stateless functional components are functions that render React components and do not maintain state, i.e. use setState. You can learn more in this tutorial or my previous post.)
我將創(chuàng)建一個(gè)簡(jiǎn)單的搜索框。 它包含兩個(gè)元素:一個(gè)搜索圖標(biāo)按鈕和一個(gè)文本框。 我將為搜索框創(chuàng)建一個(gè)無(wú)狀態(tài)的功能組件。 (無(wú)狀態(tài)功能組件是呈現(xiàn)React組件并且不維護(hù)狀態(tài)的函數(shù),即使用setState 。您可以在本教程或我之前的文章中了解更多信息 。)
SearchBox.js
SearchBox.js
import React from 'react'; import {TextField, IconButton} from 'material-ui' import SearchIcon from 'material-ui/svg-icons/action/search'; const SearchBox = ({isOpen, onClick}) => {const baseStyles = {open: {width: 300,},closed: {width: 0,},smallIcon: {width: 30,height: 30},icon: {width: 40,height: 40,padding: 5,top: 10},frame: {border: 'solid 1px black',borderRadius: 5}}; const textStyle = isOpen ? baseStyles.open : baseStyles.closed; const divStyle = Object.assign({}, textStyle, baseStyles.frame);divStyle.width += baseStyles.icon.width + 5; return (<div style={divStyle}><IconButton iconStyle={baseStyles.smallIcon} style={baseStyles.icon} onClick={() => onClick()}><SearchIcon /></IconButton><TextField name='search' style={textStyle}/></div>); }; export default SearchBox;(I’ll use the onClick callback later.)
(稍后我將使用onClick回調(diào)。)
The isOpen prop sets the SearchBox open or closed rendering.
isOpen道具將SearchBox設(shè)置為打開(kāi)或關(guān)閉渲染。
使用高階分量來(lái)分離問(wèn)題 (Using Higher Order Components to Separate Concerns)
I could change SearchBox to a regular component and add code that would open and close the text box when clicked, for example.
例如,我可以將SearchBox更改為常規(guī)組件,并添加代碼,這些代碼將在單擊時(shí)打開(kāi)和關(guān)閉文本框。
But I prefer to separate the animation from the core purpose of the search box. The search box shows/captures a query value and submits this query to some other controller. This is a subjective design decision, but it has practical benefits: I can reuse the microinteraction logic with another user input component.
但是我更喜歡將動(dòng)畫(huà)與搜索框的核心目的分開(kāi)。 搜索框顯示/捕獲查詢(xún)值,并將此查詢(xún)提交給其他控制器。 這是一個(gè)主觀的設(shè)計(jì)決定,但是它具有實(shí)際的好處:我可以將微交互邏輯與另一個(gè)用戶(hù)輸入組件一起重用。
Higher Order Components (HOC) are functions that return a new component. This component wraps a component(s) and adds functionality. I will create an HOC to add the open/close behavior to the SearchBox.
高階組件 (HOC)是返回新組件的函數(shù)。 該組件包裝組件并添加功能。 我將創(chuàng)建一個(gè)HOC來(lái)將打開(kāi)/關(guān)閉行為添加到SearchBox 。
Create expanding-animation.js
創(chuàng)建expanding-animation.js
import React, {Component} from 'react'; const makeExpanding = (Target) => {return class extends Component {constructor(props) {super(props);this.state = {isOpen: false};}onClick = () => {this.setState({isOpen: !this.state.isOpen});};render() {return (<Target {...this.props}isOpen={this.state.isOpen}onClick={this.onClick}/>);}} }; export default makeExpanding;Update App.js as follows:
如下更新App.js :
import React, {Component} from 'react'; import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';// (Make material-ui happy) // Needed for onTouchTap // http://stackoverflow.com/a/34015469/988941 import injectTapEventPlugin from 'react-tap-event-plugin'; injectTapEventPlugin();import SearchBox from './SearchBox' import makeExpanding from './expanding-animation';const ExpandingSearchBox = makeExpanding(SearchBox);class App extends Component {render() {//https://css-tricks.com/quick-css-trick-how-to-center-an-object-exactly-in-the-center/const style = {position: 'fixed',top: '50%',left: '50%',transform: 'translate(-50%, -50%)',};return (<MuiThemeProvider><div style={style}><ExpandingSearchBox/></div></MuiThemeProvider>);} } export default App;If you run npm start, you’ll have a search icon that you can click to open and close the text box.
如果您運(yùn)行npm start ,則會(huì)有一個(gè)搜索圖標(biāo),您可以單擊該圖標(biāo)以打開(kāi)和關(guān)閉文本框。
It works, but the opening and closing is jarring. An animation can smooth the effect.
它有效,但是打開(kāi)和關(guān)閉很麻煩。 動(dòng)畫(huà)可以使效果平滑。
動(dòng)畫(huà)制作 (Animations)
There are three general approaches to animations.
動(dòng)畫(huà)有三種通用方法。
CSS transitions change a property value (like width) over some time duration. The change doesn’t have to be linear; you can specify functions for changing the values.
CSS過(guò)渡會(huì)在一段時(shí)間內(nèi)更改屬性值(如width)。 變化不必是線(xiàn)性的。 您可以指定用于更改值的函數(shù)。
CSS animations change the style for an element (like size, color, and position). Each incremental style is a keyframe. You create a keyframe series to achieve a desired effect.
CSS動(dòng)畫(huà)會(huì)更改元素的樣式(如大小,顏色和位置)。 每個(gè)增量樣式都是一個(gè)關(guān)鍵幀。 您創(chuàng)建關(guān)鍵幀系列以實(shí)現(xiàn)所需的效果。
Both CSS tactics repeatedly render elements to simulate motion. You can do the calculations yourself, i.e. option (3). Several Javascript animation frameworks use this approach, managing the calculations. (I’ll use react-motion in a later example.)
兩種CSS策略都反復(fù)渲染元素以模擬運(yùn)動(dòng)。 您可以自己進(jìn)行計(jì)算,即選項(xiàng)(3)。 一些Javascript動(dòng)畫(huà)框架使用這種方法來(lái)管理計(jì)算。 (我將在后面的示例中使用react-motion。)
I will use all these techniques in the examples below, but I’ll start with CSS transitions.
我將在下面的示例中使用所有這些技術(shù),但是我將從CSS過(guò)渡開(kāi)始。
展開(kāi)搜索框 (Expanding the Search Box)
The expanding text box animation needs one CSS property: transition
擴(kuò)展的文本框動(dòng)畫(huà)需要一個(gè)CSS屬性: transition
Change expanding-animation.js as follows,
如下更改expanding-animation.js ,
import React, {Component} from 'react'; const animationStyle = {transition: 'width 0.75s cubic-bezier(0.000, 0.795, 0.000, 1.000)' }; const makeExpanding = (Target) => {return class extends Component {constructor(props) {super(props);this.state = {isOpen: false};}onClick = () => {this.setState({isOpen: !this.state.isOpen});};render() {return (<Target {...this.props}isOpen={this.state.isOpen}onClick={this.onClick}additionalStyles={{text: animationStyle, frame: animationStyle}}/>);}} }; export default makeExpanding;Looking at the change in line 21, additionalStyles, SearchBox will merge this style with it’s existing styles in line 29 and 31 below. (I’ll return to the transition CSS property in line 2 in a moment.)
看著在第21行的變化, additionalStyles , SearchBox將在第29行及以下31合并這種風(fēng)格與它的現(xiàn)有樣式。 (稍后我將在第2行中返回Transition CSS屬性。)
Update SearchBox.js
更新SearchBox.js
import React from 'react'; import {TextField, IconButton} from 'material-ui' import SearchIcon from 'material-ui/svg-icons/action/search'; const SearchBox = ({isOpen, onClick, additionalStyles}) => {const baseStyles = {open: {width: 300,},closed: {width: 0,},smallIcon: {width: 30,height: 30},icon: {width: 40,height: 40,padding: 5,top: 10},frame: {border: 'solid 1px black',borderRadius: 5}};let textStyle = isOpen ? baseStyles.open : baseStyles.closed;textStyle = Object.assign(textStyle, additionalStyles ? additionalStyles.text : {});const divStyle = Object.assign({}, textStyle, baseStyles.frame, additionalStyles ? additionalStyles.frame : {});divStyle.width += baseStyles.icon.width + 5;return (<div style={divStyle}><IconButton iconStyle={baseStyles.smallIcon} style={baseStyles.icon} onClick={() => onClick()}><SearchIcon /></IconButton><TextField name='search' style={textStyle}/></div>); }; export default SearchBox;With the styles merged, the animation will take effect.
合并樣式后,動(dòng)畫(huà)將生效。
The result is a smooth expansion of the text box width, giving the appearance it opens. The CSS transition property controls this (from line 2 in expanding-animation.js).
結(jié)果是文本框?qū)挾鹊钠交瑪U(kuò)展,使文本框具有打開(kāi)的外觀。 CSS transition屬性對(duì)此進(jìn)行控制(從expanding-animation.js第2行開(kāi)始)。
transition: 'width 0.75s cubic-bezier(0.000, 0.795, 0.000, 1.000)'I encourage you to read the documentation for the CSS transition property, as there are a variety of options. In the example, there are three parameters:
我建議您閱讀CSS過(guò)渡屬性的文檔 ,因?yàn)橛泻芏噙x擇。 在示例中,有三個(gè)參數(shù):
property to change: width
要更改的屬性: width
duration of transition: 0.75s
過(guò)渡時(shí)間: 0.75s
function to control timing: cubic-bezier(0.000, 0.795, 0.000, 1.000)’
控制時(shí)序的功能: cubic-bezier(0.000, 0.795, 0.000, 1.000)'
While I chose cubic-bezier as the function, linear or ease are among other options. There are interactive tools that help you select these values, such as this cubic-bezier builder.
當(dāng)我選擇cubic-bezier作為函數(shù)時(shí), linear或ease是其他選擇。 有一些交互式工具可以幫助您選擇這些值,例如: cubic-bezier builder 。
移動(dòng)搜索框 (Moving the Search Box)
Check out the following concept animation I found on Dribble:
看看我在Dribble上發(fā)現(xiàn)的以下概念動(dòng)畫(huà):
There are multiple elements in the interaction; but I’d like to focus on the movement of the search box to the top of the screen.
交互中包含多個(gè)元素; 但我想著重將搜索框移動(dòng)到屏幕頂部。
I can move my humble search box with a CSS transition. Create a new HOC, move-up-animation.js
我可以通過(guò)CSS轉(zhuǎn)換來(lái)移動(dòng)不起眼的搜索框。 創(chuàng)建一個(gè)新的HOC, move-up-animation.js
import React, {Component} from 'react'; const animationStyle = {transform: 'translateY(-150px)',transition: 'transform 1s ease' }; const makeMoveUp = (Target) => {return class extends Component {constructor(props) {super(props);this.state = {moveTop: false};}onClick = () => {this.setState({moveTop: !this.state.moveTop});};render() {return (<Target isOpen={true}onClick={this.onClick}additionalStyles={{text: {}, frame: this.state.moveTop ? animationStyle : {}}}/>);}} }; export default makeMoveUp; view rawmove-up-animation.js hosted with ? by GitHubThis is like the makeExpanding HOC function, except does a translation (move up). Also, the animation style applies only to the outer frame (div).
就像makeExpanding HOC函數(shù)一樣,只是進(jìn)行翻譯(向上移動(dòng))。 此外,動(dòng)畫(huà)樣式僅適用于外框( div )。
Update App.js,
更新App.js ,
import React, {Component} from 'react'; import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';// (Make material-ui happy) // Needed for onTouchTap // http://stackoverflow.com/a/34015469/988941 import injectTapEventPlugin from 'react-tap-event-plugin'; injectTapEventPlugin();import SearchBox from './SearchBox' import makeMoveUp from './move-up-animation'; const MoveUpSearchBox = makeMoveUp(SearchBox); class App extends Component {render() {//https://css-tricks.com/quick-css-trick-how-to-center-an-object-exactly-in-the-center/const style = {position: 'fixed',top: '50%',left: '50%',transform: 'translate(-50%, -50%)',};return (<MuiThemeProvider><div style={style}><MoveUpSearchBox/></div></MuiThemeProvider>);} } export default App; view rawApp.js-2 hosted with ? by GitHuband you should see
你應(yīng)該看到
Perhaps you want a bouncy effect. You could use react-motion. It is a popular React library which uses spring dynamics to control animations. (A good introduction, by Nash Vail, is here.)
也許您想要有彈性的效果。 您可以使用react-motion 。 這是一個(gè)流行的React庫(kù),它使用彈簧動(dòng)力學(xué)來(lái)控制動(dòng)畫(huà)。 ( Nash Vail的一個(gè)很好的介紹在這里 。)
npm install --save react-motionCreate spring-up-animation.js
創(chuàng)建spring-up-animation.js
import React, {Component} from 'react'; import {Motion, spring, presets} from 'react-motion' const makeSpringUp = (Target) => {return class extends Component {constructor(props) {super(props);this.state = {moveTop: false};}onClick = () => {this.setState({moveTop: !this.state.moveTop});};render() {const style = {translateY: this.state.moveTop ? spring(-150, presets.wobbly) : spring(0)};return (<Motion style={style}>{({translateY}) => (<Target isOpen={true}onClick={this.onClick}additionalStyles={{text: {},frame: {transform: `translateY(${translateY}px)`}}}/>)}</Motion>);}} }; export default makeSpringUp; view rawspring-up-animation.js hosted with ? by GitHubAs this isn’t a react-motion tutorial, I will briefly summarize how this works. React-motion wraps the animated component, Target, with its own component, Motion. (There are other react-motion components, such as TransitionMotion and Staggered Motion.)
由于這不是React運(yùn)動(dòng)教程,因此我將簡(jiǎn)要概述其工作原理。 React-motion將動(dòng)畫(huà)組件Target封裝為其自己的Motion組件。 (還有其他React運(yùn)動(dòng)組件,例如TransitionMotion和Staggered Motion 。)
React-motion interpolates, using spring dynamics, a series of interim values. It provides the values to the animated component as a style. This style determines the visual transition in the animation.
React運(yùn)動(dòng)使用彈簧動(dòng)力學(xué)插值一系列中間值。 它將值作為樣式提供給動(dòng)畫(huà)組件。 此樣式確定動(dòng)畫(huà)中的視覺(jué)過(guò)渡。
The image below shows the result (with a wobbly spring to highlight the effect).
下圖顯示了結(jié)果(帶有顫抖的彈簧以突出顯示效果)。
You could use react-motion for a range of effects. For example, you could change the text box to expand like a spring.
您可以將react-motion用于多種效果。 例如,您可以更改文本框使其像彈簧一樣展開(kāi)。
(spring-up-animation.js and move-up-animation.js have the same onClick state logic, so I refactored the common parts. Details are here.)
( spring-up-animation.js和move-up-animation.js具有相同的onClick狀態(tài)邏輯,因此我重構(gòu)了公共部分。詳細(xì)信息在這里 。)
搖動(dòng)搜索框 (Shaking the Search Box)
I want to provide feedback to the user about erroneous queries. You could use error messages, but I’d like to do something more whimsical: shake the search box.
我想向用戶(hù)提供有關(guān)錯(cuò)誤查詢(xún)的反饋。 您可以使用錯(cuò)誤消息,但我想做一些更怪異的操作:搖動(dòng)搜索框。
I could use react-motion, but I’d like to look at another technique: keyframe animation.
我可以使用react-motion,但我想看看另一種技術(shù):關(guān)鍵幀動(dòng)畫(huà)。
React-animations is a React library for keyframe animations. It injects CSS keyframes into a DOM style sheet. (The other examples have only used inline styles.)
React-animations是一個(gè)用于關(guān)鍵幀動(dòng)畫(huà)的React庫(kù)。 它將CSS關(guān)鍵幀注入到DOM樣式表中。 (其他示例僅使用內(nèi)聯(lián)樣式。)
npm install --save react-animationsI also need a library, like Radium or Aphrodite, to handle the CSS style sheet injection. I’ve chosen Aphrodite, as I’ve used it before.
我還需要一個(gè)庫(kù),例如Radium或Aphrodite ,來(lái)處理CSS樣式表注入。 我選擇了Aphrodite,就像我之前使用過(guò)的一樣。
npm install --save aphroditeCreate another HOC, shake-animation.js
創(chuàng)建另一個(gè)HOC, shake-animation.js
import React, {Component} from 'react'; import {headShake} from 'react-animations'; import {StyleSheet, css} from 'aphrodite'; const styles = StyleSheet.create({headShake: {animationName: headShake,animationDuration: '1s'} }); const makeValidationErrorAnimation = (Target) => {return class extends Component {constructor(props) {super(props);this.state = {shouldShake: false};}onClick = () => {this.setState({shouldShake: true}, () => {const self = this;setTimeout(() => self.setState({shouldShake: false}), 1000);});};render() {return (<Target isOpen={true}onClick={this.onClick}additionalStyles={{text: {}, frame: {}}}frameClass={this.state.shouldShake ? css(styles.headShake) : ''}/>);}} }; export default makeValidationErrorAnimation;There are a few key sections. Line 4 uses Aphrodite to create the style sheet for the react-animations effect, head-shake. Line 29 sets the CSS class for the animation on Target. (This requires a tweak to SearchBox to use the CSS class. Look at the use of frameClass in the source of SearchBox.js.) The onClick handler on line 17 is more complicated.
有幾個(gè)關(guān)鍵部分。 第4行使用Aphrodite創(chuàng)建用于React動(dòng)畫(huà)效果的樣式表head-shake 。 第29行在Target上設(shè)置動(dòng)畫(huà)CSS類(lèi)。 (這需要對(duì)SearchBox進(jìn)行調(diào)整才能使用CSS類(lèi)。請(qǐng)?jiān)赟earchBox.js的源代碼中查看frameClass的用法。)第17行的onClick處理程序更加復(fù)雜。
重新啟動(dòng)動(dòng)畫(huà) (Restarting an Animation)
I’d like to do the ‘head shake’ on each validation error (or whatever trigger is used). But since the animation is a CSS class, I can’t simply set the same class again; it would have no effect. This CSS Tricks post outlines a few options. The simplest is a timeout that removes the CSS animation class. When you add it again (for a new event), you’ll see the ‘head shake’.
我想對(duì)每個(gè)驗(yàn)證錯(cuò)誤(或使用任何觸發(fā)器)進(jìn)行“搖頭”操作。 但是由于動(dòng)畫(huà)是CSS類(lèi),所以我不能簡(jiǎn)單地再次設(shè)置相同的類(lèi)。 它不會(huì)有任何效果。 此CSS技巧文章概述了一些選項(xiàng)。 最簡(jiǎn)單的方法是刪除CSS動(dòng)畫(huà)類(lèi)的超時(shí)。 再次添加(針對(duì)新事件)時(shí),您會(huì)看到“搖頭”。
放在一起:組成一個(gè)復(fù)雜的組件 (Putting It Together: Composing a Complex Component)
I’ve created several HOCs for different animations. But you can also chain the HOCs to create a compound component. It will open the text box when clicked and shake on erroneous input.
我為不同的動(dòng)畫(huà)創(chuàng)建了多個(gè)HOC。 但是,您也可以鏈接HOC以創(chuàng)建復(fù)合組件。 單擊它會(huì)打開(kāi)文本框,并搖晃錯(cuò)誤的輸入。
First, you’ll need to make a few changes toSearchBox
首先,您需要對(duì)SearchBox進(jìn)行一些更改
import React from 'react'; import {TextField, IconButton} from 'material-ui' import SearchIcon from 'material-ui/svg-icons/action/search'; const baseStyles = {open: {width: 300,},closed: {width: 0,},smallIcon: {width: 30,height: 30},icon: {width: 40,height: 40,padding: 5,top: 10},frame: {border: 'solid 1px black',borderRadius: 5} }; const SearchBox = ({isOpen, query, onClick, onSubmit, onQueryUpdate, additionalStyles, frameClass}) => {const handleKeyDown = (event) => {const ENTER_KEY = 13;if (event.keyCode === ENTER_KEY) {event.preventDefault();onSubmit();}};let textStyle = isOpen ? baseStyles.open : baseStyles.closed;textStyle = Object.assign(textStyle, additionalStyles ? additionalStyles.text : {});const divStyle = Object.assign({}, textStyle, baseStyles.frame, additionalStyles ? additionalStyles.frame : {});divStyle.width += baseStyles.icon.width + 5;return (<div style={divStyle} className={frameClass ? frameClass : ''}><IconButton iconStyle={baseStyles.smallIcon} style={baseStyles.icon} onClick={() => onClick()}><SearchIcon /></IconButton><TextField name='search'style={textStyle}value={query}onKeyDown={handleKeyDown}onChange={(event, value) => onQueryUpdate(value)}/></div>); }; export default SearchBox;SearchBox is now a controlled component (fancy term for using React to manage the text box’s input value). It also provides a callback, onSubmit, for submitting the search query (when a user presses the Enter key).
SearchBox現(xiàn)在是一個(gè)受控組件 (使用React使用該術(shù)語(yǔ)來(lái)管理文本框的輸入值)。 它還提供了一個(gè)回調(diào)onSubmit ,用于提交搜索查詢(xún)(當(dāng)用戶(hù)按下Enter鍵時(shí))。
You also need to change shake-animation.js. Clicking the search icon should not cause the shake. Instead, I want another component to determine when to ‘shake’. This separates the validation logic from code that controls the animation.
您還需要更改shake-animation.js 。 單擊搜索圖標(biāo)不應(yīng)引起抖動(dòng)。 相反,我希望另一個(gè)組件來(lái)確定何時(shí)“搖動(dòng)”。 這將驗(yàn)證邏輯與控制動(dòng)畫(huà)的代碼分開(kāi)。
startShake is a flag to reset the animation. But this is an implementation detail. It should be encapsulated, as internal state, in the makeShakeAnimation HOC.
startShake是用于重置動(dòng)畫(huà)的標(biāo)志。 但這是一個(gè)實(shí)現(xiàn)細(xì)節(jié)。 應(yīng)該將其作為內(nèi)部狀態(tài)封裝在makeShakeAnimation HOC中。
import React, {Component} from 'react'; import {headShake} from 'react-animations'; import {StyleSheet, css} from 'aphrodite'; const styles = StyleSheet.create({headShake: {animationName: headShake,animationDuration: '1s'} }); const makeShakeAnimation = (Target) => {return class extends Component {constructor(props) {super(props);this.state = {startShake: props.shouldShake};}componentWillReceiveProps(nextProps) {this.setState({startShake: nextProps.shouldShake}, () => {const self = this;setTimeout(() => self.setState({startShake: false}), 1000);});//https://css-tricks.com/restart-css-animation/ for discussion on restart}render() {return (<Target {...this.props}frameClass={this.state.startShake ? css(styles.headShake) : ''}/>);}} }; export default makeShakeAnimation;startShake is dependent on shouldShake. I can use componentWillReceiveProps to respond to prop changes. (It’s parent, the validation component, provides these props.) So I moved the previous onClick logic to componentWillReceiveProps.
startShake取決于shouldShake 。 我可以使用componentWillReceiveProps來(lái)響應(yīng)道具更改。 (它的父級(jí)(驗(yàn)證組件)提供了這些道具。)因此,我將先前的onClick邏輯移至componentWillReceiveProps 。
The change in line 27, {...this.props}, passes all props to the wrapped component, Target. (I need to similarly change the render method in expanding-animation.js. The details are here.)
第27行的更改{...this.props}將所有props傳遞給包裝的組件Target 。 (我需要類(lèi)似地更改expanding-animation.js的render方法。詳細(xì)信息在這里 。)
I can now add a component that will control when to shake.
現(xiàn)在,我可以添加一個(gè)控件來(lái)控制何時(shí)搖動(dòng)。
Create search-box-controller.js
創(chuàng)建search-box-controller.js
import React, {Component} from 'react';import makeExpanding from './expanding-animation'; import makeShakingAnimation from './shake-animation';const makeAnimatedValidationSearchBox = (Target) => {const WrappedComponent = makeShakingAnimation(makeExpanding(Target));return class extends Component {constructor(props) {super(props);this.state = {query: '', hasError: false};}onQueryUpdate = (value) => {this.setState({query: value, hasError:false});};onSubmit = () => {this.setState({hasError: true});};render() {return (<WrappedComponentonQueryUpdate={this.onQueryUpdate}query={this.state.query}onSubmit={this.onSubmit}shouldShake={this.state.hasError}/>);}} };export default makeAnimatedValidationSearchBox;This is another HOC. It does not have visual elements, but it controls the logical behavior of the wrapped component. (Dan Abramov has a good post explaining such separation.) In this case, all queries as erroneous, but in a real application, I’d validate queries and connect to APIs.
這是另一個(gè)HOC。 它沒(méi)有視覺(jué)元素,但是它控制了包裝組件的邏輯行為。 ( Dan Abramov有一篇很好的文章解釋了這種分離。)在這種情況下,所有查詢(xún)都是錯(cuò)誤的,但是在實(shí)際應(yīng)用程序中,我將驗(yàn)證查詢(xún)并連接到API。
Lastly, I want to highlight that makeAnimatedValidationSearchBox is an HOC that chains two other HOCs.
最后,我想強(qiáng)調(diào)一下, makeAnimatedValidationSearchBox是一個(gè)鏈接其他兩個(gè)HOC的HOC。
const WrappedComponent =makeShakingAnimation(makeExpanding(Target));Another small update toApp.js
App.js另一個(gè)小更新
import React, {Component} from 'react'; import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';// (Make material-ui happy) // Needed for onTouchTap // http://stackoverflow.com/a/34015469/988941 import injectTapEventPlugin from 'react-tap-event-plugin'; injectTapEventPlugin(); import SearchBox from './SearchBox'import makeAnimatedValidationSearchBox from './search-box-controller'; const AnimatedSearchBox = makeAnimatedValidationSearchBox(SearchBox);class App extends Component {render() {//https://css-tricks.com/quick-css-trick-how-to-center-an-object-exactly-in-the-center/const style = {position: 'fixed',top: '50%',left: '50%',transform: 'translate(-50%, -50%)',};return (<MuiThemeProvider><div style={style}><AnimatedSearchBox/></div></MuiThemeProvider>);} } export default App;(Line 12 uses the new HOC)
(第12行使用新的HOC)
and execute run npm start
并執(zhí)行run npm start
I’ve created a compound component that uses multiple microinteractions. They are reusable and discrete.
我創(chuàng)建了使用多個(gè)微交互的復(fù)合組件。 它們是可重用和離散的。
結(jié)語(yǔ) (Wrapping Up)
I’ve sampled each of the approaches: CSS transitions, react-motion and react-animations. I wish you could pick one approach, but it’s hard to contort a single approach for all use cases. Thankfully, you can mix-and-match libraries and techniques. And you can encapsulate the details in reusable HOCs.
我已經(jīng)對(duì)每種方法進(jìn)行了采樣:CSS過(guò)渡,react-motion和react-animations。 我希望您可以選擇一種方法,但是很難針對(duì)所有用例扭曲一種方法。 值得慶幸的是,您可以混合和匹配庫(kù)和技術(shù)。 您可以將細(xì)節(jié)封裝在可重用的HOC中。
You might want to check out libraries such recompose, that make HOC creation easier.
您可能想檢出諸如recompose之類(lèi)的庫(kù),這些庫(kù)使HOC的創(chuàng)建更加容易。
The GitHub repo for this project is here.
這個(gè)項(xiàng)目的GitHub倉(cāng)庫(kù)在這里 。
Please ? this post and follow me for future stories. Thanks for reading.
請(qǐng)?這篇文章,并跟隨我的未來(lái)故事。 謝謝閱讀。
翻譯自: https://www.freecodecamp.org/news/how-to-build-animated-microinteractions-in-react-aab1cb9fe7c8/
react 交互
總結(jié)
以上是生活随笔為你收集整理的react 交互_如何在React中建立动画微交互的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 梦到自己在雨中站着是啥意思
- 下一篇: 这三种策略可以帮助女性在科技领域蓬勃发展