animation - لجوجل - فلاش بلاير للاندرويد 2017
رد-تنشيط جبل وإلغاء تحميل مكون واحد (8)
أعتقد أن استخدام
Transition
من مجموعة
react-transition-group
ربما يكون أسهل طريقة لتتبع التركيب / إلغاء التثبيت.
انها مرنة بشكل لا يصدق.
أنا أستخدم بعض الفئات لإظهار مدى سهولة استخدامها ولكن يمكنك بالتأكيد ربط الرسوم المتحركة JS الخاصة بك باستخدام
addEndListener
prop - والتي حظيت كثيرًا من الحظ باستخدام GSAP مع ذلك.
صندوق الحماية: https://codesandbox.io/s/k9xl9mkx2o
وهنا كود بلدي.
import React, { useState } from "react";
import ReactDOM from "react-dom";
import { Transition } from "react-transition-group";
import styled from "styled-components";
const H1 = styled.h1`
transition: 0.2s;
/* Hidden init state */
opacity: 0;
transform: translateY(-10px);
&.enter,
&.entered {
/* Animate in state */
opacity: 1;
transform: translateY(0px);
}
&.exit,
&.exited {
/* Animate out state */
opacity: 0;
transform: translateY(-10px);
}
`;
const App = () => {
const [show, changeShow] = useState(false);
const onClick = () => {
changeShow(prev => {
return !prev;
});
};
return (
<div>
<button onClick={onClick}>{show ? "Hide" : "Show"}</button>
<Transition mountOnEnter unmountOnExit timeout={200} in={show}>
{state => {
let className = state;
return <H1 className={className}>Animate me</H1>;
}}
</Transition>
</div>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
يجب إنجاز شيء بسيط بهذه السهولة ، لكنني أسحب شعري من مدى تعقيده.
كل ما أريد القيام به هو تنشيط وإلغاء تثبيت مكون React ، هذا كل شيء. إليك ما جربته حتى الآن ولماذا لا يعمل كل حل:
-
ReactCSSTransitionGroup
- أنا لا أستخدم فئات CSS على الإطلاق ، إنها كلها أنماط JS ، لذلك لن ينجح هذا. -
ReactTransitionGroup
- واجهة برمجة تطبيقات المستوى الأدنى هذه رائعة ، لكنها تتطلب منك استخدام رد اتصال عند اكتمال الرسوم المتحركة ، لذلك لن يعمل استخدام انتقالات CSS هنا. هناك دائمًا مكتبات للرسوم المتحركة ، والتي تؤدي إلى النقطة التالية: - GreenSock - الترخيص مقيد للغاية بالنسبة لاستخدام الأعمال IMO.
-
React Motion - يبدو هذا رائعًا ، لكن
TransitionMotion
مربكة للغاية ومعقدة للغاية لما أحتاج إليه. -
بالطبع يمكنني فقط أن أفعل الخداع مثلما يفعل Material UI ، حيث يتم تقديم العناصر ولكن تظل مخفية (
left: -10000px
) لكنني أفضل عدم السير في هذا الطريق. أنا أعتبر هذا مخترقًا ، وأريد إلغاء تثبيت المكونات الخاصة بي حتى يتم تنظيفها وعدم تكتل DOM.
أريد شيئًا سهل التنفيذ. على جبل ، تحريك مجموعة من الأساليب. عند إلغاء التثبيت ، قم بتحريك نفس مجموعة الأنماط (أو آخر). منجز. كما يجب أن يكون الأداء العالي على منصات متعددة.
لقد اصطدمت بجدار من الطوب هنا. إذا كنت أفتقد شيئًا وكانت هناك طريقة سهلة للقيام بذلك ، فأعلمني بذلك.
إليك الحل الخاص بي باستخدام API hooks الجديدة (مع TypeScript) ، بناءً على هذا المنشور ، لتأخير مرحلة إلغاء تحميل المكون:
function useDelayUnmount(isMounted: boolean, delayTime: number) {
const [ shouldRender, setShouldRender ] = useState(false);
useEffect(() => {
let timeoutId: NodeJS.Timeout;
if (isMounted && !shouldRender) {
setShouldRender(true);
}
else if(!isMounted && shouldRender) {
timeoutId = setTimeout(
() => setShouldRender(false),
delayTime
);
}
return () => clearTimeout(timeoutId);
});
return shouldRender;
}
الاستعمال:
const Parent: React.FC = () => {
const [ isMounted, setIsMounted ] = useState(true);
const shouldRenderChild = useDelayUnmount(isMounted, 500);
const mountedStyle = {opacity: 1, transition: "opacity 500ms ease-in"};
const unmountedStyle = {opacity: 0, transition: "opacity 500ms ease-in"};
const handleToggleClicked = () => {
setIsMounted(!isMounted);
}
return (
<>
{shouldRenderChild &&
<Child style={isMounted ? mountedStyle : unmountedStyle} />}
<button onClick={handleToggleClicked}>Click me!</button>
</>
);
}
رابط CodeSandbox .
إليكم سنتان: بفضلdeckele لحله. يعتمد حلي على إصداره ، فهو إصدار مكون من حالة الحالة ، يمكن إعادة استخدامه بالكامل.
هنا رمل بلدي: https://codesandbox.io/s/302mkm1m .
هنا بلدي snippet.js:
import ReactDOM from "react-dom";
import React, { Component } from "react";
import style from "./styles.css";
class Tooltip extends Component {
state = {
shouldRender: false,
isMounted: true,
}
shouldComponentUpdate(nextProps, nextState) {
if (this.state.shouldRender !== nextState.shouldRender) {
return true
}
else if (this.state.isMounted !== nextState.isMounted) {
console.log("ismounted!")
return true
}
return false
}
displayTooltip = () => {
var timeoutId;
if (this.state.isMounted && !this.state.shouldRender) {
this.setState({ shouldRender: true });
} else if (!this.state.isMounted && this.state.shouldRender) {
timeoutId = setTimeout(() => this.setState({ shouldRender: false }), 500);
() => clearTimeout(timeoutId)
}
return;
}
mountedStyle = { animation: "inAnimation 500ms ease-in" };
unmountedStyle = { animation: "outAnimation 510ms ease-in" };
handleToggleClicked = () => {
console.log("in handleToggleClicked")
this.setState((currentState) => ({
isMounted: !currentState.isMounted
}), this.displayTooltip());
};
render() {
var { children } = this.props
return (
<main>
{this.state.shouldRender && (
<div className={style.tooltip_wrapper} >
<h1 style={!(this.state.isMounted) ? this.mountedStyle : this.unmountedStyle}>{children}</h1>
</div>
)}
<style>{`
@keyframes inAnimation {
0% {
transform: scale(0.1);
opacity: 0;
}
60% {
transform: scale(1.2);
opacity: 1;
}
100% {
transform: scale(1);
}
}
@keyframes outAnimation {
20% {
transform: scale(1.2);
}
100% {
transform: scale(0);
opacity: 0;
}
}
`}
</style>
</main>
);
}
}
class App extends Component{
render(){
return (
<div className="App">
<button onClick={() => this.refs.tooltipWrapper.handleToggleClicked()}>
click here </button>
<Tooltip
ref="tooltipWrapper"
>
Here a children
</Tooltip>
</div>
)};
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
الرسوم المتحركة للدخول والخروج من التحولات أسهل بكثير من خلال react-move .
بالنسبة لأولئك الذين يفكرون في حركة رد الفعل ، فإن تحريك مكون واحد عندما يتصاعد ويفكّ يمكن أن يكون أمرًا ساحقًا في الإعداد.
هناك مكتبة تدعى react-motion-ui-pack تجعل هذه العملية أسهل كثيرًا في البدء بها. إنها مجموعة التفاف حول حركة رد الفعل ، مما يعني أنك تحصل على جميع الفوائد من المكتبة (أي أنك قادر على مقاطعة الرسوم المتحركة ، ويحدث العديد من عمليات إلغاء التثبيت في نفس الوقت).
الاستعمال:
import Transition from 'react-motion-ui-pack'
<Transition
enter={{ opacity: 1, translateX: 0 }}
leave={{ opacity: 0, translateX: -100 }}
component={false}
>
{ this.state.show &&
<div key="hello">
Hello
</div>
}
</Transition>
يُعرّف Enter الحالة النهائية للمكون ؛ الإجازة هي النمط الذي يتم تطبيقه عند إلغاء تثبيت المكون.
قد تجد أنه بمجرد استخدام حزمة واجهة المستخدم عدة مرات ، قد لا تصبح مكتبة حركة التفاعل هائلة.
كنت أيضا في حاجة ماسة للرسوم المتحركة مكون واحد. لقد تعبت من استخدام React Motion ولكني كنت أسحب شعري لمثل هذه المشكلة التافهة .. (أنا شيء). بعد بعض googling جئت عبر هذا المنصب على repo بوابة بهم. آمل أن يساعد شخص ما ..
المشار إليه من & أيضا الائتمان . هذا يعمل بالنسبة لي اعتبارا من الآن. كانت حالة الاستخدام الخاصة بي مشروطة لتحريك وإلغاء التحميل في حالة التحميل والتفريغ.
class Example extends React.Component {
constructor() {
super();
this.toggle = this.toggle.bind(this);
this.onRest = this.onRest.bind(this);
this.state = {
open: true,
animating: false,
};
}
toggle() {
this.setState({
open: !this.state.open,
animating: true,
});
}
onRest() {
this.setState({ animating: false });
}
render() {
const { open, animating } = this.state;
return (
<div>
<button onClick={this.toggle}>
Toggle
</button>
{(open || animating) && (
<Motion
defaultStyle={open ? { opacity: 0 } : { opacity: 1 }}
style={open ? { opacity: spring(1) } : { opacity: spring(0) }}
onRest={this.onRest}
>
{(style => (
<div className="box" style={style} />
))}
</Motion>
)}
</div>
);
}
}
هذا طويل بعض الشيء لكنني استخدمت كل الأحداث والأساليب المحلية لتحقيق هذه الرسوم المتحركة.
لا توجد
ReactCSSTransitionGroup
و
ReactTransitionGroup
وغيرها.
الأشياء التي استخدمتها
- رد أساليب دورة الحياة
-
حدث
onTransitionEnd
كيف يعمل هذا
-
قم بتركيب العنصر على أساس تمرير دعامة (
mounted
) ومع نمط افتراضي (opacity: 0
) -
بعد التحميل أو التحديث ، استخدم
componentDidMount
(componentWillReceiveProps
لمزيد من التحديثات) لتغيير النمط (opacity: 1
) مع مهلة (لجعله غير متزامن). -
أثناء إلغاء التثبيت ، مرر دعامة إلى المكون لتحديد إلغاء
onTransitionEnd
، قم بتغيير النمط مرة أخرى (opacity: 0
) ،onTransitionEnd
، قم بإزالة إلغاء تحميل العنصر من DOM.
مواصلة الدورة.
اذهب من خلال الكود ، فهمت. إذا كان هناك حاجة إلى أي توضيح ، يرجى ترك تعليق.
أتمنى أن يساعدك هذا.
class App extends React.Component{
constructor(props) {
super(props)
this.transitionEnd = this.transitionEnd.bind(this)
this.mountStyle = this.mountStyle.bind(this)
this.unMountStyle = this.unMountStyle.bind(this)
this.state ={ //base css
show: true,
style :{
fontSize: 60,
opacity: 0,
transition: 'all 2s ease',
}
}
}
componentWillReceiveProps(newProps) { // check for the mounted props
if(!newProps.mounted)
return this.unMountStyle() // call outro animation when mounted prop is false
this.setState({ // remount the node when the mounted prop is true
show: true
})
setTimeout(this.mountStyle, 10) // call the into animation
}
unMountStyle() { // css for unmount animation
this.setState({
style: {
fontSize: 60,
opacity: 0,
transition: 'all 1s ease',
}
})
}
mountStyle() { // css for mount animation
this.setState({
style: {
fontSize: 60,
opacity: 1,
transition: 'all 1s ease',
}
})
}
componentDidMount(){
setTimeout(this.mountStyle, 10) // call the into animation
}
transitionEnd(){
if(!this.props.mounted){ // remove the node on transition end when the mounted prop is false
this.setState({
show: false
})
}
}
render() {
return this.state.show && <h1 style={this.state.style} onTransitionEnd={this.transitionEnd}>Hello</h1>
}
}
class Parent extends React.Component{
constructor(props){
super(props)
this.buttonClick = this.buttonClick.bind(this)
this.state = {
showChild: true,
}
}
buttonClick(){
this.setState({
showChild: !this.state.showChild
})
}
render(){
return <div>
<App onTransitionEnd={this.transitionEnd} mounted={this.state.showChild}/>
<button onClick={this.buttonClick}>{this.state.showChild ? 'Unmount': 'Mount'}</button>
</div>
}
}
ReactDOM.render(<Parent />, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.2/react-with-addons.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
يمكن القيام بذلك بسهولة باستخدام مكون
CSSTransition
من مجموعة
react-transition-group
، والتي تشبه المكتبات التي ذكرتها تمامًا.
الخدعة هي أنك تحتاج إلى التفاف مكون CSSTransition
دون وجود آلية إظهار / إخفاء كما تفعل عادةً
.ie
{show && <Child>}...
وإلا فأنت تخفي
الرسوم المتحركة
ولن تعمل.
مثال:
ParentComponent.js import React from 'react'; import {CSSTransition} from 'react-transition-group'; function ParentComponent({show}) { return ( <CSSTransition classes="parentComponent-child" in={show} timeout={700}> <ChildComponent> </CSSTransition> )} ParentComponent.css // animate in .parentComponent-child-enter { opacity: 0; } .parentComponent-child-enter-active { opacity: 1; transition: opacity 700ms ease-in; } // animate out .parentComponent-child-exit { opacity: 1; } .parentComponent-child-exit-active { opacity: 0; transition: opacity 700ms ease-in; }