const states = {
	show:{
		opacity:1
	},
	hidden:{
		opacity:0
	}
}

<motion.div
	allStates={states}
	animate={'show'}
>
</motion.div>

其实你有没有发现,我们让元素发生变化,其实都是从一个状态,变化到另一个状态。如果转换成我们这种,传入一个动画信息对象的形式,其实就是一个对象,变化到另一个对象。

❗️那么既然是这样的一种变化逻辑,那么是否可以预先定义好几个状态(对象),把它们都放到一个对象中,然后给它们取不一样的名字(也就是属性名称),相当于是状态的名称,通过某个属性把这个包含多个状态对象数据的对象传入到组件中,而组件在设定需要变化到哪个状态的时候,比如使用animate属性时,直接用该状态的名字就好了。

就像下面这个代码一样,通过一个对象的不同属性来定义不同的动画信息对象,然后把这个对象传入到一个叫做allStates(假设的)的属性中,然后通过animate属性就可以用相应的状态名来实现动画效果了。

那上面代码中假设的allStates的属性,在motion组件上就是我们接下来要介绍的variants属性。

说到这里,你应该也理解了variants属性的使用方式。

首先设定一个多个动画状态的对象,其实就是一个对象里面用不同的属性名保存了不同的动画信息的对象。然后把这个多状态的动画信息对象传给组件的variants属性。

传入之后,乍看一下是没有任何效果的。我们需要在animate属性中传入某个状态的名称,也就是传入variants属性的对象中的某个属性名。你用哪个属性名,其实就是使用了哪个动画对象的信息,那么元素就会发生相应的变化效果。

比如,我们在animate属性上使用👇🏼:

const animations = {
	show:{
		opacity:1
	},
	hidden:{
		opacity:0
	}
}
<motion.div
	variants={animations}
	animate={'show'}
>
</motion.div>

这里我们要记得,组件的哪些属性是可以接受动画信息对象的,就是能接受状态名称的。比如我们已经知道的animateinitial

#

variants

使用这种variants会有一些额外的优势:

  1. 👉通过属性名,具有语义化更直观和容易理解。

  2. 👉不同的元素可以复用,节约内存空间。

  3. 👉相同的状态名称,可以实现父子元素联动。

第一点,我相信大家都能理解,毕竟通过属性名把状态名称设定得很清晰易懂的话,一旦用这个状态名字,通过代码就能很明显能知道这个元素会进行一个怎样的变化。

第二点,比如我可以让不同的元素都是用同一个状态对象,这样我就避免了去设置多个一模一样的对象了,提高的写代码的效率,也减少了不必要的内存浪费。

第三点,如果父元素子元素使用一样的属性名的状态对象去设置元素(并不需要两者传入的是同一个状态对象,只要状态对象的属性名是一样的)。只要父元素使用用相应的属性名(状态名称)进行变化,子元素会自动触发动画同名状态的变化。

子元素甚至都不需要去通过animate传入状态名称。注意,必须要父元素通过animate来传入状态名称才会生效,不能传入动画信息对象。

const list = {
  visible: { opacity: 1 },
  hidden: { opacity: 0 },
}

const item = {
  visible: { opacity: 1, x: 0 },
  hidden: { opacity: 0, x: -100 },
}

return (
  <motion.ul
    initial="hidden"
    animate="visible"
    variants={list}
  >
    <motion.li variants={item} />
    <motion.li variants={item} />
    <motion.li variants={item} />
  </motion.ul>
)

#

使用variants的优点

const variants = {
  visible: i => ({
    opacity: 1,
    transition: {
      delay: i * 0.3,
    },
  }),
  hidden: { opacity: 0 },
}

return items.map((item, i) => (
  <motion.li
    custom={i}
    animate="visible"
    variants={variants}
  />
))

动画信息对象在设置具体某个状态名称的数据时,可以使用函数的形式,这个函数可以有一个参数,这个参数真正接受到的就是组件上通过custom属性传入的值,这个函数需要返回一个动画信息的对象,这个对象中可以利用这个函数的参数做一些动态处理。

#

通过variants实现动态传值