通过Framer-motion库,实现布局变化是一件非常轻松的事情,而且会比我们常规的写法有更好的动画性能。

比如,我们可以在使用flex布局的时候通过改变justify-content的值来让元素发生变化,比如下面这个例子就是把父元素的justify-content的值在flex-startflex-end之间切换。

而这一切的关键,就是要在motion组件上加上一个layout属性。

<motion.div layout />
<motion.div layout transition={{ duration: 0.3 }} />

注意,上面这个按钮的例子中,layout属性不是添加到包裹圆球的父元素上,而是添加到白色圆球本身:

 <motion.div
        style={{
          width:180,
          backgroundColor:'#FFFFFF88',
          borderRadius:'60px',
          display:'flex',
          alignItems:'center', 
          justifyContent: buttonRight ? 'flex-end':'flex-start', // 这里改变 <-
          padding:10
        }}
        onTap={()=>{
          setButtonState(!buttonRight)
        }}
      >
        <motion.div
            layout // 设置在白色圆球元素上,即子元素上 <-
            style={{
            width:60,
            height:60,
            backgroundColor:'white',
            borderRadius:60,
          }}
          >
        </motion.div>
    </motion.div>

当组件触发重新渲染,渲染后的元素布局发生改变,就会触发相应的变化效果。

所谓布局变化核心就是两大方面,一个是尺寸变化,一个是位置变化,具体来说,包括但不限于以下四类常见的情况:

列表重新排序

1

元素自身变化

2

父元素布局设置变化

3

改变父元素的justify-content设置,从flex-start改成了flex-end

其他任何布局变化

4

改变一个元素的宽度,让父元素和平级子元素都同步发生过渡变化

改变渲染的顺序,元素会有发生位置变化的动画效果

这里都是直接通过style属性设置相关的改变,一个是width,另一个位置发生变化设置的是和定位相关的left属性的变化

motion组件的布局动画本质上是经过计算变化的具体值,然后通过transform来实现各种变化过渡的效果。但是有时候,通过transform的变化可能导致元素的子元素有一些扭曲或者奇怪的变化,如果出现了,你可以给子元素设置一个layout属性,但一定要注意,这个子元素也需要是👉motion组件。

🎉所以,不管是父元素或者子元素,如果你希望它能够在布局产生变化时有自然的过渡效果,都可以试着给元素添加👉layout属性,但是前提这个元素必须是👉motion元素。

下面这个案例,你可以看到设置layout和没设置layout的区别:

#

layout过渡设置

transform同样会导致boxShadowborderRadius发生畸变。如果你要让这两个属性通过👉👉motion组件的方式进行动态变化,Motion组件会自动的对这些问题进行纠正。

如果你不需要让这两个属性发生变化,那么只要通过style来设置他们即可。

如果motion组件只有layout变化,那么直接通过transition进行设置即可

如果有其他的变化效果,同时你先单独对layout变化进行过渡的设置,可以在transition属性里面单独设置一个layout来进行设置。

<motion.div
  layoutScroll
  style={{ overflow: "scroll" }}
/>

#

layoutScroll

如果你想要可滚动的元素也实现正确的布局变化效果,那你需要给滚动的容器上添加上layoutScroll属性。

这个属性会让容器元素在计算一些布局变化时会考虑到子元素的因滚动产生偏移量。

<motion.div
  layoutScroll
  style={{ overflow: "scroll" }}
/>