2017-08-14 43 views
14

Napisałem aplikację React, używając przejść CSS. Ale te przejścia nie działają poprawnie w niektórych komponentach. W my app tylko komponenty, które poruszają się w górę, działają dobrze, te, które poruszają się w dół, poruszają się natychmiast bez animacji. (. Chcę im obu ruchów z animacją)React css transition nie działa poprawnie

Oto CSS ja tam stosowane:

div.canvas { 
    position: absolute; 
    top: 90px; 
    left: 60px; 
    width: 640px; 
    height: 480px; 
    border: 1px solid #999; 
    background: white; 

} 

div.canvas-rect { 
    position: relative; 
    margin-left: 20px; 
    margin-top: 10px; 
    height: 20px; 
    background: green; 

    transition: all 1s linear; 
    -moz-transition: all 1s linear; /* Firefox 4 */ 
    -webkit-transition: all 1s linear; /* Safari 和 Chrome */ 
    -o-transition: all 1s linear; /* Opera */ 

} 

AKTUALIZACJA:

ja też zbudowali codepen.io project pokazać problem. Ma pełny kod tego projektu demonstracyjnego.

Próbowałem dodać wpis dziennika componentDidUpdate, componentDidMount i componentWillUnmount metod, aby pokazać, czy są składnikiem są ponownie tworzone lub aktualizowane, to pokazuje, że wszystkie one są aktualizowane (nie nowo utworzony lub usunięty) każdą sekundę .

+0

Nie możemy debugować zaledwie 2 reguł CSS, trzeba umieścić fragment kodu roboczego odtwarzając problem – LGSon

+0

@LGSon Przykro nam, I został zbudowany i projekt codepen.io wkrótce zaktualizuje pytanie. – cmal

+0

Po prostu zamieniając wartości 'top' na niektóre, zaczynają animować również w dół. Chyba musisz sprawdzić, jak te wartości są włączane na przedmiotach. https://codepen.io/anon/pen/ZJazQa ... należy również pamiętać, że nieprzypisane właściwości powinny zawsze być poprzedzone prefiksem w podziękowaniu CSS – LGSon

Odpowiedz

11

Po tym, jak zacząłem nagrodę, ponieważ mam również ten problem, w końcu znalazłem coś, co wydaje się być problemem.

Gdy używasz pozycji bezwzględnej (względnej, tak jak w twoim przypadku), jeśli ponownie wyświetlisz całą listę, React ponownie uporządkuje elementy w DOM (tak jak powiedziałeś, elementy nie są odtworzone, właśnie zaktualizowane). Ale to stwarza problem z przejściami ... najwyraźniej, jeśli poruszasz elementem podczas przejścia, to kończysz cięcie animacji.

Tak więc, w przypadkach, w których chcesz używać pozycji bezwzględnej, kluczową koncepcją jest renderowanie kontenerów swoich elementów tylko raz (w tym przypadku tylko div) i zmiana wewnętrznej zawartości tylko na podstawie nowego zamówienia. Jeśli chcesz dodać więcej elementów, po prostu dodaj je na końcu.

Zmodyfikowalem twój codepen tak, aby odzwierciedlał to, co mówię. Mój przykład jest bardzo głupi, ponieważ właśnie utworzyłem 4 elementy div typu ad-hoc, ale ilustruje to ideę: utwórz tyle kontenerów, ile potrzebujesz, ale NIE używaj mapy, która odtwarza je za każdym razem, albo twoje przejścia zostaną przerwane.

https://codepen.io/damianmr/pen/boEmmy?editors=0110

const ArrList = ({ 
    arr 
}) => { 
    return (
    <div style={{position: 'relative'}}> 
     <div className={`element element-${arr[0]} index-${arr[0]}`}>{arr[0]}</div> 
     <div className={`element element-${arr[1]} index-${arr[1]}`}>{arr[1]}</div> 
     <div className={`element element-${arr[2]} index-${arr[2]}`}>{arr[2]}</div> 
     <div className={`element element-${arr[3]} index-${arr[3]}`}>{arr[3]}</div> 
    </div> 
); 
} 

Tak, problem jest w zasadzie jak utworzyć statyczną listę pojemników i jak iterację tej listy tak, że pierwszy pojemnik sprawia, że ​​pierwszy element danych, drugą Container drugi element, itp.

Mam nadzieję, że to pomaga, ten problem doprowadzał mnie do szaleństwa! :)

+1

Mam nadzieję, że mógłbym głosować na tę odpowiedź tysiąc razy ... dzięki! – MarkoCen

+0

Nie ma za co! @MarkoCen – damianmr

1

Jeśli usuwasz element z wirtualnego DOM, to reaguje zaktualizuje jego zawartość, więc nie zobaczysz animacji. Możesz użyć albo: react-transition-group LUB powiedz aplikacji, aby poczekała x ms, zanim zaktualizowała domenę po wywołaniu zdarzenia LUB użyj widoczności, aby przełączać się między ukrytym i wyświetlającym zamiast całkowicie usunąć z DOM.

+0

. Ale elementy nie zostały usunięte z V-DOM, tylko zaktualizowano komponent. Zaktualizowałem pytanie do tego. – cmal

1

Za każdym razem odtwarzałeś elementy DOM.
Należy zdefiniować wartość klucza zbierania. Zmieniłem wartość klucza '' + el na '' + index.

<div key={'' + index} className={'element element-' + el + ' index-' + index} > 

Wystarczy zmienić css właściwości tylko :)

1

Można oszukać React za pomocą index jako klucza. Jeśli myślisz o el i index jako pozycji początkowej (indeks) i pozycji końcowej (el), element przesunął się do starej pozycji końcowej przed końcem przejścia, a gdy już się tam znajduje, zostaje przejęty przez nowy początek pozycja i (indeks) są przełączane, aby dopasować się do nowej konfiguracji. Dzieje się tak dlatego, że ustawiając key w reagującym elemencie, wirtualny DOM zawsze interpretuje go jako ten sam element. I ze względu na to, masz rację w ustawianiu indeksu jako "id" w ogóle.

Wykonałem przykład roboczy tylko poprzez zmianę indeksu/el (i ustawienie pozycji elementu na absolutną).

const {combineReducers, createStore} = Redux; 
 
const { Provider, connect } = ReactRedux; 
 

 
const ArrList = ({ 
 
    arr 
 
}) => (
 
    <div>{ 
 
    arr.map((el, index)=> 
 
      <div 
 
      key={""+index} 
 
      className={`element element-${el}` + ` index-${el}`} 
 
      > 
 
      {el} 
 
      </div>) } 
 
    </div> 
 
) 
 
     
 
const mapStateToArrList = (state) => { 
 
    return { 
 
    arr: state.appReducer.arr 
 
    } 
 
}; 
 

 
const App = connect(mapStateToArrList, null)(ArrList); 
 

 
const initialState = { 
 
    arr: [1, 2, 3, 4] 
 
} 
 

 
const appReducer = (state = initialState, action) => { 
 
    switch(action.type) { 
 
    case "tick": 
 
     return { 
 
     ...state, 
 
     arr: _.shuffle(state.arr) 
 
     } 
 
    default: 
 
     return state 
 
    } 
 
} 
 

 
const reducer = combineReducers({ 
 
    appReducer 
 
}) 
 

 

 
const store = createStore(reducer) 
 

 
ReactDOM.render(
 
    <Provider store={store}> 
 
    <App /> 
 
    </Provider>, 
 
    document.getElementById('root') 
 
) 
 

 
const dispatcher =() => { 
 
    store.dispatch({ 
 
    type: "tick" 
 
    }) 
 
    setTimeout(dispatcher, 1000) 
 
} 
 

 
dispatcher()
.element { 
 
    position: absolute; 
 
    height: 20px; 
 
    background: green; 
 
    margin-left: 20px; 
 
    margin-top: 20px; 
 

 
    text-align: right; 
 
    color: white; 
 
    line-height: 20px; 
 

 
    transition: all 1s ease-in; 
 
    -moz-transition: all 1s ease-in; /* Firefox 4 */ 
 
    -webkit-transition: all 1s ease-in; /* Safari 和 Chrome */ 
 
    -o-transition: all 1s ease-in; /* Opera */ 
 

 
} 
 

 
.element-1 { 
 
    width: 20px; 
 
} 
 

 
.element-2 { 
 
    width: 40px; 
 
} 
 

 
.element-3 { 
 
    width: 60px; 
 
} 
 

 
.element-4 { 
 
    width: 80px; 
 
} 
 

 
.index-1 { 
 
    top: 20px; 
 
} 
 

 
.index-2 { 
 
    top: 40px; 
 
} 
 

 
.index-3 { 
 
    top: 60px; 
 
} 
 

 
.index-4 { 
 
    top: 80px; 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/3.7.2/redux.js"></script> 
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/5.0.6/react-redux.js"></script> 
 

 
<div id="root"></div>