摘要:原文地址項目地址關于中使用效果,官網上的解釋如下當元素插入到樹或者從樹中移除的時候,屬性提供變換的效果,可以使用來定義變化效果,也可以使用來定義首先第一個函數是將元素插入,函數實現調用了實現代碼如下寫的好的代碼就是文檔,從注釋和命名上就
src/transition
原文地址
項目地址
關于 vue 中使用 transition 效果,官網上的解釋如下:
With Vue.js’ transition system you can apply automatic transition effects when elements are inserted into or removed from the DOM. Vue.js will automatically add/remove CSS classes at appropriate times to trigger CSS transitions or animations for you, and you can also provide JavaScript hook functions to perform custom DOM manipulations during the transition.
當元素插入到 DOM 樹或者從 DOM 樹中移除的時候, transition 屬性提供變換的效果,可以使用 css 來定義變化效果,也可以使用 JS 來定義
src/transition/index.jsimport { before, remove, transitionEndEvent } from "../util/index" /** * Append with transition. * * @param {Element} el * @param {Element} target * @param {Vue} vm * @param {Function} [cb] */ export function appendWithTransition (el, target, vm, cb) { applyTransition(el, 1, function () { target.appendChild(el) }, vm, cb) } ...
首先第一個函數是將元素插入 DOM, 函數實現調用了 applyTransition, 實現代碼如下:
/** * Apply transitions with an operation callback. * * @param {Element} el * @param {Number} direction * 1: enter * -1: leave * @param {Function} op - the actual DOM operation * @param {Vue} vm * @param {Function} [cb] */ 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 是要操作的元素, direction 代表是插入還是刪除, op 代表具體的操作方法函數, vm 從之前的代碼或者官方文檔可以知道指 vue 實例對象, cb 是回調函數
vue 將解析后的transition作為 DOM 元素的屬性 __v_trans ,這樣每次操作 DOM 的時候都會做以下判斷:
如果元素沒有被定義了 transition
如果元素沒有 jshook 且 css transition 的定義不支持
如果元素還沒有編譯完成
如果元素有父元素且父元素沒有編譯完成
存在以上其中一種情況的話則直接執行操作方法 op 而不做變化,否則執行:
var action = direction > 0 ? "enter" : "leave" transition[action](op, cb)
除了添加,還有插入和刪除兩個操作方法:
export function beforeWithTransition (el, target, vm, cb) { applyTransition(el, 1, function () { before(el, target) }, vm, cb) } export function removeWithTransition (el, vm, cb) { applyTransition(el, -1, function () { remove(el) }, vm, cb) }
那么 transitoin 即 el.__v_trans 是怎么實現的,這個還得繼續深挖
src/transition/queue.jsimport { nextTick } from "../util/index" let queue = [] let queued = false /** * Push a job into the queue. * * @param {Function} job */ export function pushJob (job) { queue.push(job) if (!queued) { queued = true nextTick(flush) } } /** * Flush the queue, and do one forced reflow before * triggering transitions. */ function flush () { // Force layout var f = document.documentElement.offsetHeight for (var i = 0; i < queue.length; i++) { queue[i]() } queue = [] queued = false // dummy return, so js linters don"t complain about // unused variable f return f }
這是 transition 三個文件中的第二個,從字面量上理解是一個隊列,從代碼上看實現的是一個任務隊列,每當調用 pushJob 的時候,都會往任務隊列 queue 里面推一個任務,并且有一個標識queued, 如果為 false 則會在 nextTick 的時候將 queued 置為 true同時調用 flush 方法,這個方法會執行所有在任務隊列 queue 的方法,并將 queued 置為 false
還記得 nextTick 的實現嗎?實現在 src/util/env 中:
/** * Defer a task to execute it asynchronously. Ideally this * should be executed as a microtask, so we leverage * MutationObserver if it"s available, and fallback to * setTimeout(0). * * @param {Function} cb * @param {Object} ctx */ export const nextTick = (function () { var callbacks = [] var pending = false var timerFunc function nextTickHandler () { pending = false var copies = callbacks.slice(0) callbacks = [] for (var i = 0; i < copies.length; i++) { copies[i]() } } /* istanbul ignore if */ if (typeof MutationObserver !== "undefined") { var counter = 1 var observer = new MutationObserver(nextTickHandler) var textNode = document.createTextNode(counter) observer.observe(textNode, { characterData: true }) timerFunc = function () { counter = (counter + 1) % 2 textNode.data = counter } } else { timerFunc = setTimeout } return function (cb, ctx) { var func = ctx ? function () { cb.call(ctx) } : cb callbacks.push(func) if (pending) return pending = true timerFunc(nextTickHandler, 0) } })()
官網的解釋如下
Defer the callback to be executed after the next DOM update cycle. Use it immediately after you’ve changed some data to wait for the DOM update.
即在下一次 DOM 更新循環中執行回調,用在你需要等待 DOM 節點更新后才能執行的情況,實現的簡單方法是利用 setTimeout 函數,我們知道 setTimeout 方法會將回調函數放入時間隊列里,并在計時結束后放到事件隊列里執行,從而實現異步執行的功能,當然尤大只把這種情況作為備用選擇,而采用模擬DOM創建并利用觀察者MutationObserver監聽其更新來實現:
var observer = new MutationObserver(nextTickHandler) // 創建一個觀察者 var textNode = document.createTextNode(counter) // 創建一個文本節點 observer.observe(textNode, { // 監聽 textNode 的 characterData 是否為 true characterData: true }) timerFunc = function () { // 每次調用 nextTick,都會調用timerFunc從而再次更新文本節點的值 counter = (counter + 1) % 2 // 值一直在0和1中切換,有變化且不重復 textNode.data = counter }
不了解MutationObserver 和 characterData 的可以參考MDN的解釋: MutaitionObserver
& CharacterData
mutationObserver 例子
flush 函數聲明變量f: var f = document.documentElement.offsetHeight 從注釋上看應該是強制DOM更新,因為調用offsetHeight的時候會讓瀏覽器重新計算出文檔的滾動高度的緣故吧
src/transition/transition.jstransition 實現了元素過渡變換的邏輯和狀態,Transition 的原型包含了 enter, enterNextTick, enterDone, leave, leaveNextTick, leaveDone 這幾個狀態,以 enter 為例子:
/** * Start an entering transition. * * 1. enter transition triggered * 2. call beforeEnter hook * 3. add enter class * 4. insert/show element * 5. call enter hook (with possible explicit js callback) * 6. reflow * 7. based on transition type: * - transition: * remove class now, wait for transitionend, * then done if there"s no explicit js callback. * - animation: * wait for animationend, remove class, * then done if there"s no explicit js callback. * - no css transition: * done now if there"s no explicit js callback. * 8. wait for either done or js callback, then call * afterEnter hook. * * @param {Function} op - insert/show the element * @param {Function} [cb] */ p.enter = function (op, cb) { this.cancelPending() this.callHook("beforeEnter") this.cb = cb addClass(this.el, this.enterClass) op() this.entered = false this.callHookWithCb("enter") if (this.entered) { return // user called done synchronously. } this.cancel = this.hooks && this.hooks.enterCancelled pushJob(this.enterNextTick) }
cancelPending 只有在 enter 和 leave 里被調用了,實現如下:
/** * Cancel any pending callbacks from a previously running * but not finished transition. */ p.cancelPending = function () { this.op = this.cb = null var hasPending = false if (this.pendingCssCb) { hasPending = true off(this.el, this.pendingCssEvent, this.pendingCssCb) this.pendingCssEvent = this.pendingCssCb = null } if (this.pendingJsCb) { hasPending = true this.pendingJsCb.cancel() this.pendingJsCb = null } if (hasPending) { removeClass(this.el, this.enterClass) removeClass(this.el, this.leaveClass) } if (this.cancel) { this.cancel.call(this.vm, this.el) this.cancel = null } }
調用 cancelPending 取消之前的正在運行的或者等待運行的 js 或 css 變換事件和類名,然后觸發腳本 beforeEnter, 添加 enterClass 類名,執行具體的元素插入操作,將 entered 置為 false,因為此時還沒有完成插入操作,然后執行 callHookWithCb,最后確定 this.cancel 的值以及進入下一步操作 enterNextTick, 最后操作為 enterDone
/** * The "cleanup" phase of an entering transition. */ p.enterDone = function () { this.entered = true this.cancel = this.pendingJsCb = null removeClass(this.el, this.enterClass) this.callHook("afterEnter") if (this.cb) this.cb() }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/88380.html
摘要:用來定義元素兩種狀態之間的過渡。到目前為止,我們利用完全模擬了第一部分我們使用實現的功能,而且看上去更簡潔。附上利用來實現該方案的代碼用于參考。由于代碼效果時好時壞,猜測可能與的容器相關。 背景 在日常的項目開發中,我們會很經常的遇見如下的需求: 在瀏覽器頁面中,當鼠標移動到某個部分后,另一個部分在延遲若干時間后出現 在鼠標移除該區域后,另一部分也在延遲若干時間后消失 我相信這是一...
摘要:至此算是找到了源碼位置。至此進入過渡的部分完畢。在動畫結束后,調用了由組件生命周期傳入的方法,把這個元素的副本移出了文檔流。這篇并沒有去分析相關的內容,推薦一篇講非常不錯的文章,對構造函數如何來的感興趣的同學可以看這里 Vue transition源碼分析 本來打算自己造一個transition的輪子,所以決定先看看源碼,理清思路。Vue的transition組件提供了一系列鉤子函數,...
摘要:綁定輪播事件然后是鼠標移入移出事件的綁定鼠標移入移出事件移入時停止輪播播放的定時器,移出后自動開始下一張的播放。 通過上一篇文章的學習,我們基本掌握了一個輪子的封裝和開發流程。那么這次將帶大家開發一個更有難度的項目——輪播圖,希望能進一步加深大家對于面向對象插件開發的理解和認識。 So, Lets begin! 目前項目使用 ES5及UMD 規范封裝,所以在前端暫時只支持標簽的引入方式...
摘要:在元素被插入之前生效,在元素被插入之后的下一幀移除。在整個進入過渡的階段中應用,在元素被插入之前生效,在過渡動畫完成之后移除。這個類可以被用來定義進入過渡的過程時間,延遲和曲線函數。版及以上定義進入過渡的結束狀態。 基本概念 Vue 在插入、更新或者移除 DOM 時,提供多種不同方式的應用過渡效果 在 CSS 過渡和動畫中自動應用 class 可以配合使用第三方 CSS 動畫庫,如...
摘要:在元素被插入之前生效,在元素被插入之后的下一幀移除。在整個進入過渡的階段中應用,在元素被插入之前生效,在過渡動畫完成之后移除。這個類可以被用來定義進入過渡的過程時間,延遲和曲線函數。版及以上定義進入過渡的結束狀態。 基本概念 Vue 在插入、更新或者移除 DOM 時,提供多種不同方式的應用過渡效果 在 CSS 過渡和動畫中自動應用 class 可以配合使用第三方 CSS 動畫庫,如...
閱讀 1849·2023-04-26 01:58
閱讀 1982·2019-08-30 11:26
閱讀 2730·2019-08-29 12:51
閱讀 3495·2019-08-29 11:11
閱讀 1183·2019-08-26 11:54
閱讀 2096·2019-08-26 11:48
閱讀 3478·2019-08-26 10:23
閱讀 2384·2019-08-23 18:30