最近公司的项目选型使用了vue,因此用vue开发了一个项目,期间在处理一些动画的时候,发现vue-transition虽然用起来简单,可是局限性很大,好比没法处理一个组件中父子元素的联动动画。这就极大得限制了咱们的发挥,你只能进行单层次的动画,相似modal这种两种动画联动的就很难作,你极可能须要分红两个组件来作,这就不符合组件化的原则。vue
因此打算研读一下源码,而后研究一下如何解决这个问题。node
既然是看transition,那么首先就得狙击transition
指令,而后transition
指令代码如此简单:react
// (/src/directives/internal/transition.js) export default { priority: TRANSITION, update (id, oldId) { var el = this.el // resolve on owner vm var hooks = resolveAsset(this.vm.$options, 'transitions', id) id = id || 'v' // apply on closest vm el.__v_trans = new Transition(el, id, hooks, this.el.__vue__ || this.vm) if (oldId) { removeClass(el, oldId + '-transition') } addClass(el, id + '-transition') } }
在这里咱们指令在el
上加上了一个__v_trans
属性,这个属性是一个Transition
的实例,因此咱们去看看这个实例干了什么app
// (/src/transition/transition.js) export default function Transition (el, id, hooks, vm) { ... }
这就是一个保存这个过渡动画应该包含的一些属性和钩子,咱们仍是不知道何时经过什么方法调用了动画组件化
这时候我回头去看了vue的文档,在transition的介绍里有这么一句:动画
transition 特性能够与下面资源一块儿用:this
v-if
v-show
v-for (只为插入和删除触发)
动态组件 (介绍见组件)
在组件的根节点上,而且被 Vue 实例 DOM 方法(如 vm.$appendTo(el))触发。code
这时候我就怀疑只有特定的场景才能触发transition,而触发的关键就在这些指令里面,因而我就去看v-if
指令,而后在他插入节点的时候发现了这一句代码:生命周期
this.frag = this.factory.create(this._host, this._scope, this._frag) this.frag.before(this.anchor)
这个factory
是什么?,接着找ip
this.elseFactory = new FragmentFactory(this.vm, next)
他是一个FragmentFactory
,在这个FragmentFactory
里面我看到了这一个方法:
function singleBefore (target, withTransition) { this.inserted = true var method = withTransition !== false ? beforeWithTransition : before method(this.node, target, this.vm) if (inDoc(this.node)) { this.callHook(attach) } }
貌似看到了一些曙光,咱们终于看到跟transition有关的东西,这里咱们继续找到beforeWithTransition
这个方法,代码以下:
export function beforeWithTransition (el, target, vm, cb) { applyTransition(el, 1, function () { before(el, target) }, vm, cb) }
这里调用了applyTransition,代码以下:
export function applyTransition (el, direction, op, vm, cb) { var transition = el.__v_trans if ( !transition || // skip if there are no js hooks and CSS transition is // not supported (!transition.hooks && !transitionEndEvent) || // skip transitions for initial compile !vm._isCompiled || // if the vm is being manipulated by a parent directive // during the parent's compilation phase, skip the // animation. (vm.$parent && !vm.$parent._isCompiled) ) { op() if (cb) cb() return } var action = direction > 0 ? 'enter' : 'leave' transition[action](op, cb) }
在这里咱们终于看到了el.__v_trans
这个属性,那么这个回路基本就算走完了。
而后我去看了一下v-show
指令,因而发现,还有更简单的方法。。。
apply (el, value) { if (inDoc(el)) { applyTransition(el, value ? 1 : -1, toggle, this.vm) } else { toggle() } function toggle () { el.style.display = value ? '' : 'none' } }
直接applyTransition
就能够调用了
如今咱们知道为何v-transition
是只能单点的了,由于本质上他只能做用于特定指令所影响的特定元素,他的实现方式并非相似于react的TransitionGroup
这样经过给子组件增长生命周期在经过子组件在生命周期自定义动画的方式,vue的局限性表露无遗,让我以为很奇怪做者为何选择这种方式,难道真的只是为了下降使用难度?
问题提出来了,就得想办法了
我得想一想。。。