最近公司的項目選型使用了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的侷限性表露無遺,讓我以爲很奇怪做者爲何選擇這種方式,難道真的只是爲了下降使用難度?
問題提出來了,就得想辦法了
我得想一想。。。