模板语言中的 key 和动画

这是一篇旧文,其中的内容可能已经过时。

近期微信公开发布了小程序,一并推出的还有模板语言 WXML 和样式表 WXSS。其中在渲染数组的语法中,列表项提供了一个wx:key属性,如果你也熟悉 React 的话,没错,它的含义和用途与 React 中的 key 是一模一样的:

当数据改变触发渲染层重新渲染的时候,会校正带有 key 的组件,框架会确保他们被重新排序,而不是重新创建,以确保使组件保持自身的状态,并且提高列表渲染时的效率。

如果你的列表会后续更新的话,那么你应该为你的列表项提供一个在上下文中唯一的 key。或者,即使是静态列表,也这么做,养成一个好习惯。

以上都是老生常谈的话题了,现在来讲点稍微不一样的。key 可以不用在列表中吗?我们来看看在单独的元素上使用 key 会有什么效果。

这是一个简单的报价实时展示。注意到当价格连续走高或者走低两次之后,组件连续两次渲染成div.up因为前后的 key 不同,所以经历了一次销毁重建,动画触发了两次。如果把key={this.state.price}拿掉,那么 React 只更新div.up里边的内容,第二次动画则不会触发。

来看另外一个例子。

这是一个带轮播的报价展示,巧妙地运用了 key 和 css 位移动画。先稍微看下代码,然后思考,为什么我要把两个列表项的 key 写成'prev' + this.state.prev.name'current' + this.state.current.name,而不是直接用this.state.prev.namethis.state.current.name呢?如果写成了后者,那么考虑更新时情况:key 由“金”和“银”变成“银”和“铜”,则“银”这个组件不会被销毁,而是直接被移动到了第一项,所以动画不会触发。在 key 中加入不同的前缀,是为了让两个列表在更新时都销毁重建。

总结:在开发动画时,可以使用 key 和 css 动画的组合拳,不光写起来优雅,也很好理解。而不要用什么定时器去删类名以触发动画,有时候多看看各家的开发文档,会找到更合适的技术方案。

参考文档:

  1. https://facebook.github.io/react/docs/reconciliation.html#keys