最近有个需求,一个列表上下移动要有简单过渡效果,在网上找了找没找到,多是我搜的关键词不对?vue
试了试 Vue 的transition-group
,也没有达到预期的效果,而后就花了点时间作了一个操做Demo。git
在线演示:jsrun.net/hdyKpgithub
Demo源码:github.com/thinkupp/vu…bash
某列的数据由 X 位置上升到 Y 位置的过渡效果动画
这个过渡效果一共由三部分组成:ui
Y行
位置插入X行
位置的数据,添加一个高度展开效果,并使该行的数据不可见X行
数据不可见, 并添加一个高度收起效果X行
的DOM, 设置为固定定位fixed
, top
取X行距离body
的位置(offsetTop
), 并作一个向上移动效果到Y行
位置这里仅仅依靠`offsetTop`并不许确,具体见文章后面的内容. url
来看一个放慢版的效果,加了个边框而且没有设置visibility
属性,看的会更明了:spa
简单说一下。.net
第一部分描述一个让目标位置底下全部行有一个向下移动的过程。3d
第二部分描述那个移动的行消失的过程。
第三部分描述一个移动的过程。
为了避免污染数据渲染出来的视图,除了固定定位的那个盒子是直接操做DOM,以外的两个效果是经过操做数据+类名实现的。
缘由:因为 v-for 的时候给每行的key
是index
,数据源发生变化后会致使受影响的元素的index
也发生改变。
解决:将key
的值由index
更换为item
(惟一值, 在这里item
指的是图片url) 。
当位置频繁改变的时候要清除上一次的动画遗留元素,否则元素会发生各类错乱,这个很容易想的到,错误演示就不录了,看一下完成的效果。
缘由:第一部分插入X行
数据形成,由于两条相同的数据重复的item
会形成重复的key
。
解决:在进行第一部分的时候将原来那一行的key
改成其它值。
<li :key="closeIndex === index ? Date.now() : item"></li>
复制代码
我用的时间戳,其实理论上来说只要能保持惟一写什么均可以,反正这一行数据将在动画结束后从数据中删除。
仅仅依靠offsetTop
计算位置是不许确的,当页面发生滚动后元素与Body的实际距离就不是offsetTop
的值了。应该用offsetTop
减去scrollTop
,这样才是元素当前与Body的实际距离。
/*
* 计算盒子当前距离body的距离
* @param {HTMLElement} ele 要计算位置的盒子
* @returns {number} 当前位置距离body的距离
* */
calcTop(ele) {
let offsetTop = ele.offsetTop;
let offsetParent = ele.offsetParent;
while (offsetParent) {
offsetTop += offsetParent.offsetTop;
offsetParent = offsetParent.offsetParent;
}
return offsetTop - (document.body.scrollTop || document.documentElement.scrollTop)
}
复制代码
获取 scrollTop 的方式根据项目不一样也不一样,并非全部的状况下均可以经过 document.body.scrollTop || document.documentElement.scrollTop 获取到正确的内容,具体区分项目
描述有点乱,但愿能给也遇到此问题的朋友提供一个思路,有误的地方麻烦你们及时指正。