Как добавить переход при перемещении элементов в состоянии или реквизита, отображаемого на карте - PullRequest
0 голосов
/ 03 сентября 2018

Скажем, я рендерил список из реквизита состояния, используя функцию .map.

Я хочу изменить порядок списка; поэтому я меняю порядок в моем штате или в моей опоре. Изменение отражается соответственно, но как мне добавить плавный переход в этом случае, чтобы пользователь чувствовал, что он / она что-то сделал? В противном случае пользовательский опыт ухудшается.

Он - основная идея того, чего я хочу достичь

import React from "react";
import ReactDOM from "react-dom";

import "./styles.css";

export class App extends React.Component {
  constructor() {
    super();
    this.state = {
      items: [
        { key: 0, name: "Hello" },
        { key: 0, name: "Sello" }, // move this down with transition
        { key: 0, name: "Wello" }, // move this up with transition
        { key: 0, name: "Zello" },
        { key: 0, name: "Pello" },
        { key: 0, name: "Aello" }
      ]
    };
  }
  reShuffle = () => {
    this.setState({
      items: this.state.items.map((item, index) => {
        if (index === 1) {
          return this.state.items[2];
        }
        if (index === 2) {
          return this.state.items[1];
        }
        return item;
      })
    });
  };
  render() {
    return (
      <div className="App" style={{ transition: "all 0.5s ease" }}>
        <button onClick={this.reShuffle}> Click Me </button>
        {this.state.items.map(item => <li key={item.key}> {item.name} </li>)}
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Легко копируется отсюда https://codesandbox.io/s/648z61kvrn

1 Ответ

0 голосов
/ 03 сентября 2018

При выполнении css-перехода на реагирующем элементе вам нужно иметь дело с дополнительным состоянием: самим переходом.

Итак, сначала вы изменяете состояние ваших компонентов, так что переход css изменит их, затем вы изменяете состояние в конце перехода, чтобы заставить реакцию соответствовать стилю компонента в конце перехода.

В случае, когда вы нажимаете, чтобы переключить элемент, вы должны вычислить изменение CSS, которое будет иметь тот же эффект, что и переключение элементов, а затем, когда переход завершится, вы фактически переключите элементы.

Нам потребуется добавить свойство top к элементам и соответствующий ключ:

constructor() {
super();
this.state = {
  items: [
    { key: 0, name: "Hello", top: 0 },
    { key: 1, name: "Sello", top: 0 }, // move this down
    { key: 2, name: "Wello", top: 0 }, // move this up
    { key: 3, name: "Zello", top: 0 },
    { key: 4, name: "Pello", top: 0 },
    { key: 5, name: "Aello", top: 0 }
  ],
  transitioning: {}
};
this.itemTransitionCount = 0;

}

Обратите внимание на itemTransitionCount для дальнейшего использования.

Сначала оберните элементы <li> в элемент <ul> и прикрепите ссылку к <ul>:

ulLoad = c => (this.ulDom = c);
render() {
    ...
    <ul
        ref={this.ulLoad}
        style={{ position: "relative", display: "inline-block" }}
    >
        {
            this.state.items.map(item => (
                <li
                    key={item.key}
                    onTransitionEnd={this.itemTransitionEnd}
                    style={{
                        transition: item.top ? "top 0.5s ease" : "none",
                        position: "relative",
                        top: item.top
                    }}
                >
                    {item.name}
                </li>
            ))
        }
    </ul>
    ....
}

Это позволит вычислить относительное положение детей <li> с

Затем измените ваш обработчик перестановки следующим образом:

reShuffle = () => {
this.setState({
  items: this.state.items.map((item, index) => {
    if (index === 1) {
      const top2 = this.ulDom.children[2].offsetTop;
      const top1 = this.ulDom.children[1].offsetTop;
      const top = top2 - top1;
      return { ...this.state.items[1], top };
    }
    if (index === 2) {
      const top1 = this.ulDom.children[1].offsetTop;
      const top2 = this.ulDom.children[2].offsetTop;
      const top = top1 - top2;
      return { ...this.state.items[2], top };
    }
    return item;
  })
});

Этот код будет инициировать верхний переход, который мы хотим установить для элементов li => анимация переключения будет происходить во время следующего рендеринга.

Мы завершим обе анимации с помощью обработчика onTransitionEnd (проверка на evt.target! == evt.currentTarget есть, потому что пузырьки событий перехода присутствуют, потому что оба элемента вызовут событие, но мы хотим, чтобы действовать один раз в конце обоих переходов):

itemTransitionEnd = evt => {
if (evt.target !== evt.currentTarget) return;
// alert("transitionEnd");
this.itemTransitionCount++;
if (this.itemTransitionCount < 2) return;
this.itemTransitionCount = 0;
this.setState({
  items: this.state.items.map((item, index) => {
    if (index === 1) {
      return { ...this.state.items[2], top: 0 };
    }
    if (index === 2) {
      return { ...this.state.items[1], top: 0 };
    }
    return item;
  })
});

};

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

Это иллюстрирует двухэтапный рендеринг для анимации перехода CSS в React.

Рабочая песочница здесь

...