vue源码阅读—14—扩展之transition
<style> .fade-enter-active, .fade-leave-active { transition: opacity 5s; } .fade-enter, .fade-leave-to { opacity: 0; } </style> <script> let vm = new Vue({ el: "#app", template: '<div id="demo">' + '<button v-on:click="show = !show">' + "Toggle" + "</button>" + '<transition :appear="true" name="fade">' + '<p v-if="show">hello</p>' + "</transition>" + "</div>", data() { return { show: true, }; }, }); </script>
transition组件功能:本身不提供动画,动画需要用户自己写;主要是在不同的情况下自动调用css,实现过渡效果;
一、transition流程
在transition组件的render阶段,执行render阶段,先通过插槽,拿到transition组件里的子节点;
拿到第一个子节点;
判断transition是否是一个组件的根节点
给p标签添加一个key属性_transition-1-p;
通过extractTransitionData方法获取一个值,并赋值给child.data.transition属性;
extractTransitions方法主要是,定义一个data对象,这个把所有vm.options.propsData(就是我们在占位符组件上定义的属性)都重新赋值给data。
如果有._partentListeners就是我们在占位符组件上调用的监听事件,也可以说是钩子函数,before-enter、enter、after-enter、enter-cancelled等等;
最后一个返回一个子节点的vnode,vnode.data.transition是有值的;
然后我们会执行invokeCreateHooks方法,然后就会调用_enter函数,然后因为vnode.data.show是undefined,所以执行enter(vnode);
在enter方法中,会执行resolveTransition方法,它会给这个对象拓展很多属性,比如enterAcitveClass;
拿到过渡动画,即我们定义的css;
"fade-enter"
fade-enter-active"
"fade-enter-to"
然后开始获取钩子函数,但是因为我们没有定义transition组建的钩子函数,所以都为undefined;
先执行beforeEnterHook,因为没有定义钩子函数,所以不执行;
然后给el也就是p标签添加startSlass, 也就是我们自己定义的fade-enter css属性,
然后再添加fade-enter-active属性;
然后会执行nextFrame,
先把startClass 即fade-start给删除掉,因为已经到了active的时候了。
然后再吧toClass添加进去;
然后等到css属性里的transition执行完,开始执行whenTRansitionEnd方法;
所以说呀,动画过渡这些效果还是css本生提供的,vue只是帮助我们自动在合适的时机调动这个css而已;
这个方法主要是执行我们定义的cb回调函数;
然后这个回调函数把toClass和activeClass都删除掉;
然后如果有afterEnterHook钩子还会调用;
然后结束;
二、总结
三、transiton-group
首先调用render函数;
然后给每个子节点vnode.data.transition赋值为我们定义的transitionDAta;
然后后面就是正常的渲染出来数据了,没啥说的;
当我们点击啊add时,会触发数据变化,然后渲染watcher重新渲染;
重新调用transition组件的render函数;
prevChildren是渲染之前的children,是9个vnode子节点;
rawChildren是这次的子节点,因为数据已经变化了,所以是10个vnode子节点;
这一次prevChildren是有值的,就是上次的9ge子节点,
然后我们会给上次的9个子节点的data拓展transition属性和pos属性;
pos属性是节点所在的相对浏览器的位置;
然后把所有的上次渲染过这次还要渲染的节点保存到kept中;
为后续update钩子做准备;
等到我们重新渲染后,
我们发现,数字10已经被渲染出来了,在浏览器中中已经有这个span节点和它的空间了,但是为什么看不到它的位置呢?因为在css中的v-enter即初始状态,我们设置的是
执行recordPostin方法,记录每个新节点的位置,给vnode.data.newPos;
执行applyTranslation方法,给每个子节点拓展一个偏移的transition属性;即vnode.elm.stype.transfom;还拓展一个属性vnode.data.moved = true;
然后
1.给每个子节点添加movecalss
2.将vnode.elm.style.tranfom置为0,这样就会有过渡动画产生;
3.添加一个transition事件结束的事件监听器;
四、总结