代码之家  ›  专栏  ›  技术社区  ›  Prasanna

如何在移动使用地图呈现的状态或属性中的项目时添加过渡

  •  0
  • Prasanna  · 技术社区  · 6 年前

    假设我正在使用 .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 回复  |  直到 6 年前
        1
  •  1
  •   remix23    6 年前

    在对react元素进行css转换时,需要处理一个附加状态:转换本身。

    因此,首先更改组件的状态,以便CSS转换将更改它们,然后更改转换结束时的状态,使react与转换结束时组件的样式匹配。

    在您的例子中,当您单击切换元素时,您必须计算一个与切换元素效果相同的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;
    

    }

    记下itemtrantincount以备以后使用。

    首先包装你的 <li> 元素在 <ul> 元素并将引用附加到 <UL & GT; :

    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>
        ....
    }
    

    这将允许计算子对象的相对位置 <理工大学; S

    然后以这种方式更改重组处理程序:

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

    };

    上面的代码实际上会在转换结束时切换元素并重置其相对顶部(转换计数也会为下一个转换重置)。

    这说明了在React中对CSS转换动画进行两步渲染。

    Working sandbox here