Closed Right10Arthur closed 4 years ago
主要原因应该不是TweenOne的错,希望不管父组件用的是不是有问题,子组件足够鲁棒强壮。 原listsort在mouseup时会在动画结束时通过state去重新调整组件中子节点的顺序,原代码如下,我用TS整理过listSort
public onMouseUp = (e: any) => {
const draging = this.draging
if (!draging) {
return;
}
document.body.style.overflow = 'null';
this.props.onEventChange(e, 'up');
if (this.props.dragClassName) {
/**在拖拽完成的dom的css中,去除props.dragClassName*/
draging.dragingDom.className = `${draging.dragingDom.className.replace(this.props.dragClassName, '').trim()}`;
}
const childAnimation = this.state.childDragingTweenOneAnimation.map((anim: AnimInfo, index: number) => {
if (draging.oldIdx !== index)
return anim;
else {/**结束时只对拖动的结点进行收场动画 */
...省略
return {
...lastAnim,
onComplete: () => {
/**动画完成时,修改children的排序 */
const children = this.changeChildIndex(this.state.children, draging.oldIdx, draging.newIdx);
const callbackBool = draging.oldIdx !== draging.newIdx;
this.setState(
{ listStyle: {}, childDragingStyle: [], children, childDragingTweenOneAnimation: [], }
, () => {
/**通知组件使用者数据做了修改 */
callbackBool && this.props.onChange(children);
delete this.draging;
})
);
},
};
}
});
this.setState({ childDragingTweenOneAnimation: childAnimation });
};
改为用process.nextTick包一下就好了
onComplete: () => {
/**动画完成时,修改children的排序 */
process.nextTick(() => {
console.log( `${draging.oldIdx} ==> ${draging.newIdx}`)
const children = this.changeChildIndex(this.state.children, draging.oldIdx, draging.newIdx);
const callbackBool = draging.oldIdx !== draging.newIdx;
this.setState(
{ listStyle: {}, childDragingStyle: [], children, childDragingTweenOneAnimation: [], }
, () => {
/**通知组件使用者数据做了修改 */
callbackBool && this.props.onChange(children);
delete this.draging;
})
}
);
},
引发这个bug的原因是,会有机率释放的时候,被动移动的兄弟节点在react按children更新后尚有未完成动画,这样会从未完成的动画跳变成最后的结果,则这时如果不用nextTick包一下,则会引发TweenOne报上方我提的err,也就是onComplete完成后,TweenOne后续还在计算动画? 这个bug可以如下重现,不断将第一个节点移动到第二个节点,视觉上都是对的情况下,会有很大机率出现0==>0也就是收尾的时候算出没变?什么原因我会继续跟踪一下。 6ListSort.tsx:250 0 ==> 1 2ListSort.tsx:250 0 ==> 0 另,非常感谢阿里AntD的前端兄弟的开源代码,觉的从可读性还是可以再有所提高,也希望能为您们助一臂之力,再次感谢! 觉的可读性提高的最明显的是onMouseMove的代码,我改写的如下
public onMouseMove = (e: any) => {
const draging = this.draging
if (!draging) {
return;
}
draging.mouseXY.x = e.touches === undefined ? e.clientX : e.touches[0].clientX;
draging.mouseXY.y = e.touches === undefined ? e.clientY : e.touches[0].clientY;
const newStyleS = this.state.childDragingStyle;
let childAnimation = this.state.childDragingTweenOneAnimation;
const { oldStyleS, oldIdx } = draging;
if (this.props.animType === 'x') {
// 懒得写现在没用。。。做成组件后加
newStyleS[oldIdx].left = draging.mouseXY.x! - draging.mouseXY.startX + draging.mouseXY.left;
}
else {
/*1.跟据鼠标位置 实时 修改拖动的节点的位置,
修改拖动节点的style.top实时改变位置*/
const newTop = newStyleS[oldIdx].top = draging.mouseXY.y! - draging.mouseXY.startY + draging.mouseXY.top;
/*2.计算拖动节点 要占的新的索引
和拖动前的位置比对,鼠标落在哪个节点中就要占哪个位置*/
let newIdx = 0;
for (const oldStyle of oldStyleS) {
if (newTop < (oldStyle.top + oldStyle.height)) break;
++newIdx;
}
newIdx = draging.newIdx = Math.min(newIdx, oldStyleS.length - 1)
/*3.修改列表中的其它节点的位置
修改Anim.top会有动效*/
childAnimation = childAnimation.map((anim: AnimInfo, idx: any) => {
if (idx === oldIdx) {//当前拖动的节点,不参与通过动效去修改节点位置
return anim
}
if (newIdx === oldIdx) {//拖动的节点回到拖动前的索引,其它节点都返回到拖动前的top
return { top: oldStyleS[idx].top };
}
const height = oldStyleS[oldIdx].height + oldStyleS[oldIdx].marginHeight;
if (newIdx > oldIdx) {/**当新的位置在旧的位置下方时 */
if (idx > oldIdx && idx <= newIdx)
return { top: oldStyleS[idx].top - height };
}
else if (oldIdx > newIdx) {/**当新的位置在旧的位置上方时 */
if (idx < oldIdx && idx >= newIdx)
return { top: oldStyleS[idx].top + height };
}
return { top: oldStyleS[idx].top };
});
}
this.setState({ childDragingStyle: newStyleS, childDragingTweenOneAnimation: childAnimation });
};
sortlist出错的原因找到啦,因为onMouseMove通过this.draging是不是为空来判断当前拖拽是否结束,所以不要在onmouseup->动画结束->setState结束时->delete this.draging;,而在onmouseup函数最后就delete this.draging; 原代码和我有一样的问题,他是用的onmouseup->动画结束->setState结束时->this.isDrage = false;
TweenOne.js:317 Uncaught TypeError: Cannot read property 'totalTime' of null at TweenOne.frame (TweenOne.js:317) at Object.raf [as func] (TweenOne.js:367) at ticker.js:77 at Array.forEach ()
at ./node_modules/rc-tween-one/es/ticker.js.p.tick (ticker.js:76)
frame @ TweenOne.js:317
raf @ TweenOne.js:367
(anonymous) @ ticker.js:77
./node_modules/rc-tween-one/es/ticker.js.p.tick @ ticker.js:76
requestAnimationFrame (async)
./node_modules/raf/index.js.module.exports @ index.js:64
./node_modules/rc-tween-one/es/ticker.js.p.tick @ ticker.js:84
requestAnimationFrame (async)
./node_modules/raf/index.js.module.exports @ index.js:64
./node_modules/rc-tween-one/es/ticker.js.p.tick @ ticker.js:84
requestAnimationFrame (async)
./node_modules/raf/index.js.module.exports @ index.js:64
./node_modules/rc-tween-one/es/ticker.js.p.tick @ ticker.js:84