React CSS transition работает неправильно

Я написал приложение React, используя CSS-переходы. Но эти переходы не работают правильно в некоторых компонентах. В Мои приложения, только компоненты, которые движутся вверх, работают хорошо, те, кто движется вниз, перемещаются мгновенно без анимации. (Я хочу, чтобы они оба двигались с анимацией.)

вот CSS, который я использовал там:

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 */

}

обновление:

Я также построил codepen.IO project показать проблема. Он имеет полный код этого демо-проекта.

Я попытался добавить запись журнала в componentDidUpdate, componentDidMount и componentWillUnmount методы чтобы показать, создаются ли эти компоненты повторно или обновляются, он показывает, что все они обновляются (не создаются повторно или удаляются) каждую секунду.

4 ответов


Ну, после того, как я начал щедрость, потому что у меня также есть эта проблема, я, наконец, нашел то, что кажется проблемой.

когда вы используете абсолютную позицию (или относительную, как в вашем случае), если вы каждый раз перерисовываете весь список, React будет переупорядочивать элементы в DOM (как вы сказали, элементы не воссоздаются, просто обновляются). Но это создает проблему с переходами... по-видимому, если вы перемещаете элемент во время выполнения перехода, вы заканчиваете вырезание анимации.

Итак, для случаев, в которых вы хотите использовать position absolute, ключевой концепцией является визуализация контейнеров ваших элементов один раз (в этом случае просто divs) и изменение только внутреннего содержимого на основе нового порядка. Если вам нужно добавить больше элементов, просто добавьте их в конце.

Я изменил ваш код, чтобы он отражал то, что я говорю. Мой пример очень глуп, потому что я только что создал 4 ad-hoc divs, но он иллюстрирует идею: создайте как можно больше контейнеры, как вам нужно, но не используйте карту, которая воссоздает их каждый раз, или ваши переходы будут вырезаны.

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>
  );
}

Итак, проблема в том, как вы создаете статический список контейнеров и как вы перебираете этот список, чтобы первый контейнер отображал первый элемент ваших данных, второй контейнер-второй элемент и т. д.

надеюсь, что это поможет, эта проблема меня это тоже сводило с ума! :)


Если вы удаляете элемент из виртуального DOM, то react обновит его содержимое, поэтому вы не увидите анимации. Что вы можете сделать, это либо использовать react-transition-group или скажите вашему приложению подождать X МС перед обновлением dom после вызова события или использовать видимость для переключения между скрытым и отображением вместо того, чтобы полностью удалить его из DOM.


вы можете обмануть реагировать с помощью index как ключ. Если вы думаете о el и index в качестве начальной позиции (индекс) и конечной позиции (el) элемент переместился в старую конечную позицию к концу перехода, и когда он там, он захватывается новой начальной позицией и (индекс) переключается в соответствии с новой настройкой. Это потому, что когда вы установите key в элементе в react виртуальный DOM всегда будет интерпретировать его как один и тот же элемент. И ради этого, вы правы в настройке индекса как " id " в целом.

Я сделал рабочий пример только путем переключения index / el (и установки положения элемента в абсолют).

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>

вы воссоздали DOM элементы каждый раз.
Вы должны определить значение ключа collect. Я изменил значение вашего ключа '' + el to '' + index.

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

просто изменить