Vue 源碼解析之一:transition

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

問題提出來了,就得想辦法了

我得想一想。。。

相關文章
相關標籤/搜索