摘要:原文地址項目地址關(guān)于中使用效果,官網(wǎng)上的解釋如下當元素插入到樹或者從樹中移除的時候,屬性提供變換的效果,可以使用來定義變化效果,也可以使用來定義首先第一個函數(shù)是將元素插入,函數(shù)實現(xiàn)調(diào)用了實現(xiàn)代碼如下寫的好的代碼就是文檔,從注釋和命名上就
src/transition
原文地址
項目地址
關(guān)于 vue 中使用 transition 效果,官網(wǎng)上的解釋如下:
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) } ...
首先第一個函數(shù)是將元素插入 DOM, 函數(shù)實現(xiàn)調(diào)用了 applyTransition, 實現(xiàn)代碼如下:
/** * 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) }
寫的好的代碼就是文檔,從注釋和命名上就能很好的理解這個函數(shù)的作用, el 是要操作的元素, direction 代表是插入還是刪除, op 代表具體的操作方法函數(shù), vm 從之前的代碼或者官方文檔可以知道指 vue 實例對象, cb 是回調(diào)函數(shù)
vue 將解析后的transition作為 DOM 元素的屬性 __v_trans ,這樣每次操作 DOM 的時候都會做以下判斷:
如果元素沒有被定義了 transition
如果元素沒有 jshook 且 css transition 的定義不支持
如果元素還沒有編譯完成
如果元素有父元素且父元素沒有編譯完成
存在以上其中一種情況的話則直接執(zhí)行操作方法 op 而不做變化,否則執(zhí)行:
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 是怎么實現(xiàn)的,這個還得繼續(xù)深挖
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 三個文件中的第二個,從字面量上理解是一個隊列,從代碼上看實現(xiàn)的是一個任務(wù)隊列,每當調(diào)用 pushJob 的時候,都會往任務(wù)隊列 queue 里面推一個任務(wù),并且有一個標識queued, 如果為 false 則會在 nextTick 的時候?qū)?queued 置為 true同時調(diào)用 flush 方法,這個方法會執(zhí)行所有在任務(wù)隊列 queue 的方法,并將 queued 置為 false
還記得 nextTick 的實現(xiàn)嗎?實現(xiàn)在 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) } })()
官網(wǎng)的解釋如下
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 更新循環(huán)中執(zhí)行回調(diào),用在你需要等待 DOM 節(jié)點更新后才能執(zhí)行的情況,實現(xiàn)的簡單方法是利用 setTimeout 函數(shù),我們知道 setTimeout 方法會將回調(diào)函數(shù)放入時間隊列里,并在計時結(jié)束后放到事件隊列里執(zhí)行,從而實現(xiàn)異步執(zhí)行的功能,當然尤大只把這種情況作為備用選擇,而采用模擬DOM創(chuàng)建并利用觀察者MutationObserver監(jiān)聽其更新來實現(xiàn):
var observer = new MutationObserver(nextTickHandler) // 創(chuàng)建一個觀察者 var textNode = document.createTextNode(counter) // 創(chuàng)建一個文本節(jié)點 observer.observe(textNode, { // 監(jiān)聽 textNode 的 characterData 是否為 true characterData: true }) timerFunc = function () { // 每次調(diào)用 nextTick,都會調(diào)用timerFunc從而再次更新文本節(jié)點的值 counter = (counter + 1) % 2 // 值一直在0和1中切換,有變化且不重復(fù) textNode.data = counter }
不了解MutationObserver 和 characterData 的可以參考MDN的解釋: MutaitionObserver
& CharacterData
mutationObserver 例子
flush 函數(shù)聲明變量f: var f = document.documentElement.offsetHeight 從注釋上看應(yīng)該是強制DOM更新,因為調(diào)用offsetHeight的時候會讓瀏覽器重新計算出文檔的滾動高度的緣故吧
src/transition/transition.jstransition 實現(xiàn)了元素過渡變換的邏輯和狀態(tài),Transition 的原型包含了 enter, enterNextTick, enterDone, leave, leaveNextTick, leaveDone 這幾個狀態(tài),以 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 里被調(diào)用了,實現(xiàn)如下:
/** * 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 } }
調(diào)用 cancelPending 取消之前的正在運行的或者等待運行的 js 或 css 變換事件和類名,然后觸發(fā)腳本 beforeEnter, 添加 enterClass 類名,執(zhí)行具體的元素插入操作,將 entered 置為 false,因為此時還沒有完成插入操作,然后執(zhí)行 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() }
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/88380.html
摘要:用來定義元素兩種狀態(tài)之間的過渡。到目前為止,我們利用完全模擬了第一部分我們使用實現(xiàn)的功能,而且看上去更簡潔。附上利用來實現(xiàn)該方案的代碼用于參考。由于代碼效果時好時壞,猜測可能與的容器相關(guān)。 背景 在日常的項目開發(fā)中,我們會很經(jīng)常的遇見如下的需求: 在瀏覽器頁面中,當鼠標移動到某個部分后,另一個部分在延遲若干時間后出現(xiàn) 在鼠標移除該區(qū)域后,另一部分也在延遲若干時間后消失 我相信這是一...
摘要:至此算是找到了源碼位置。至此進入過渡的部分完畢。在動畫結(jié)束后,調(diào)用了由組件生命周期傳入的方法,把這個元素的副本移出了文檔流。這篇并沒有去分析相關(guān)的內(nèi)容,推薦一篇講非常不錯的文章,對構(gòu)造函數(shù)如何來的感興趣的同學(xué)可以看這里 Vue transition源碼分析 本來打算自己造一個transition的輪子,所以決定先看看源碼,理清思路。Vue的transition組件提供了一系列鉤子函數(shù),...
摘要:綁定輪播事件然后是鼠標移入移出事件的綁定鼠標移入移出事件移入時停止輪播播放的定時器,移出后自動開始下一張的播放。 通過上一篇文章的學(xué)習(xí),我們基本掌握了一個輪子的封裝和開發(fā)流程。那么這次將帶大家開發(fā)一個更有難度的項目——輪播圖,希望能進一步加深大家對于面向?qū)ο蟛寮_發(fā)的理解和認識。 So, Lets begin! 目前項目使用 ES5及UMD 規(guī)范封裝,所以在前端暫時只支持標簽的引入方式...
摘要:在元素被插入之前生效,在元素被插入之后的下一幀移除。在整個進入過渡的階段中應(yīng)用,在元素被插入之前生效,在過渡動畫完成之后移除。這個類可以被用來定義進入過渡的過程時間,延遲和曲線函數(shù)。版及以上定義進入過渡的結(jié)束狀態(tài)。 基本概念 Vue 在插入、更新或者移除 DOM 時,提供多種不同方式的應(yīng)用過渡效果 在 CSS 過渡和動畫中自動應(yīng)用 class 可以配合使用第三方 CSS 動畫庫,如...
摘要:在元素被插入之前生效,在元素被插入之后的下一幀移除。在整個進入過渡的階段中應(yīng)用,在元素被插入之前生效,在過渡動畫完成之后移除。這個類可以被用來定義進入過渡的過程時間,延遲和曲線函數(shù)。版及以上定義進入過渡的結(jié)束狀態(tài)。 基本概念 Vue 在插入、更新或者移除 DOM 時,提供多種不同方式的應(yīng)用過渡效果 在 CSS 過渡和動畫中自動應(yīng)用 class 可以配合使用第三方 CSS 動畫庫,如...
閱讀 1865·2023-04-26 01:58
閱讀 1991·2019-08-30 11:26
閱讀 2735·2019-08-29 12:51
閱讀 3501·2019-08-29 11:11
閱讀 1190·2019-08-26 11:54
閱讀 2104·2019-08-26 11:48
閱讀 3486·2019-08-26 10:23
閱讀 2391·2019-08-23 18:30