1import { inBrowser, isIE9, warn } from 'core/util/index'2import { mergeVNodeHook } from 'core/vdom/helpers/index'3import { activeInstance } from 'core/instance/lifecycle'45import {6 once,7 isDef,8 isUndef,9 isObject,10 toNumber,11 isFunction12} from 'shared/util'1314import {15 nextFrame,16 resolveTransition,17 whenTransitionEnds,18 addTransitionClass,19 removeTransitionClass20} from 'web/runtime/transition-util'2122import type { VNodeWithData } from 'types/vnode'23import VNode from 'core/vdom/vnode'2425export function enter(vnode: VNodeWithData, toggleDisplay?: () => void) {26 const el: any = vnode.elm2728 // call leave callback now29 if (isDef(el._leaveCb)) {30 el._leaveCb.cancelled = true31 el._leaveCb()32 }3334 const data = resolveTransition(vnode.data.transition)35 if (isUndef(data)) {36 return37 }3839 /* istanbul ignore if */40 if (isDef(el._enterCb) || el.nodeType !== 1) {41 return42 }4344 const {45 css,46 type,47 enterClass,48 enterToClass,49 enterActiveClass,50 appearClass,51 appearToClass,52 appearActiveClass,53 beforeEnter,54 enter,55 afterEnter,56 enterCancelled,57 beforeAppear,58 appear,59 afterAppear,60 appearCancelled,61 duration62 } = data6364 // activeInstance will always be the <transition> component managing this65 // transition. One edge case to check is when the <transition> is placed66 // as the root node of a child component. In that case we need to check67 // <transition>'s parent for appear check.68 let context = activeInstance69 let transitionNode = activeInstance.$vnode70 while (transitionNode && transitionNode.parent) {71 context = transitionNode.context72 transitionNode = transitionNode.parent73 }7475 const isAppear = !context._isMounted || !vnode.isRootInsert7677 if (isAppear && !appear && appear !== '') {78 return79 }8081 const startClass = isAppear && appearClass ? appearClass : enterClass82 const activeClass =83 isAppear && appearActiveClass ? appearActiveClass : enterActiveClass84 const toClass = isAppear && appearToClass ? appearToClass : enterToClass8586 const beforeEnterHook = isAppear ? beforeAppear || beforeEnter : beforeEnter87 const enterHook = isAppear ? (isFunction(appear) ? appear : enter) : enter88 const afterEnterHook = isAppear ? afterAppear || afterEnter : afterEnter89 const enterCancelledHook = isAppear90 ? appearCancelled || enterCancelled91 : enterCancelled9293 const explicitEnterDuration: any = toNumber(94 isObject(duration) ? duration.enter : duration95 )9697 if (__DEV__ && explicitEnterDuration != null) {98 checkDuration(explicitEnterDuration, 'enter', vnode)99 }100101 const expectsCSS = css !== false && !isIE9102 const userWantsControl = getHookArgumentsLength(enterHook)103104 const cb = (el._enterCb = once(() => {105 if (expectsCSS) {106 removeTransitionClass(el, toClass)107 removeTransitionClass(el, activeClass)108 }109 // @ts-expect-error110 if (cb.cancelled) {111 if (expectsCSS) {112 removeTransitionClass(el, startClass)113 }114 enterCancelledHook && enterCancelledHook(el)115 } else {116 afterEnterHook && afterEnterHook(el)117 }118 el._enterCb = null119 }))120121 if (!vnode.data.show) {122 // remove pending leave element on enter by injecting an insert hook123 mergeVNodeHook(vnode, 'insert', () => {124 const parent = el.parentNode125 const pendingNode =126 parent && parent._pending && parent._pending[vnode.key!]127 if (128 pendingNode &&129 pendingNode.tag === vnode.tag &&130 pendingNode.elm._leaveCb131 ) {132 pendingNode.elm._leaveCb()133 }134 enterHook && enterHook(el, cb)135 })136 }137138 // start enter transition139 beforeEnterHook && beforeEnterHook(el)140 if (expectsCSS) {141 addTransitionClass(el, startClass)142 addTransitionClass(el, activeClass)143 nextFrame(() => {144 removeTransitionClass(el, startClass)145 // @ts-expect-error146 if (!cb.cancelled) {147 addTransitionClass(el, toClass)148 if (!userWantsControl) {149 if (isValidDuration(explicitEnterDuration)) {150 setTimeout(cb, explicitEnterDuration)151 } else {152 whenTransitionEnds(el, type, cb)153 }154 }155 }156 })157 }158159 if (vnode.data.show) {160 toggleDisplay && toggleDisplay()161 enterHook && enterHook(el, cb)162 }163164 if (!expectsCSS && !userWantsControl) {165 cb()166 }167}168169export function leave(vnode: VNodeWithData, rm: Function) {170 const el: any = vnode.elm171172 // call enter callback now173 if (isDef(el._enterCb)) {174 el._enterCb.cancelled = true175 el._enterCb()176 }177178 const data = resolveTransition(vnode.data.transition)179 if (isUndef(data) || el.nodeType !== 1) {180 return rm()181 }182183 /* istanbul ignore if */184 if (isDef(el._leaveCb)) {185 return186 }187188 const {189 css,190 type,191 leaveClass,192 leaveToClass,193 leaveActiveClass,194 beforeLeave,195 leave,196 afterLeave,197 leaveCancelled,198 delayLeave,199 duration200 } = data201202 const expectsCSS = css !== false && !isIE9203 const userWantsControl = getHookArgumentsLength(leave)204205 const explicitLeaveDuration: any = toNumber(206 isObject(duration) ? duration.leave : duration207 )208209 if (__DEV__ && isDef(explicitLeaveDuration)) {210 checkDuration(explicitLeaveDuration, 'leave', vnode)211 }212213 const cb = (el._leaveCb = once(() => {214 if (el.parentNode && el.parentNode._pending) {215 el.parentNode._pending[vnode.key!] = null216 }217 if (expectsCSS) {218 removeTransitionClass(el, leaveToClass)219 removeTransitionClass(el, leaveActiveClass)220 }221 // @ts-expect-error222 if (cb.cancelled) {223 if (expectsCSS) {224 removeTransitionClass(el, leaveClass)225 }226 leaveCancelled && leaveCancelled(el)227 } else {228 rm()229 afterLeave && afterLeave(el)230 }231 el._leaveCb = null232 }))233234 if (delayLeave) {235 delayLeave(performLeave)236 } else {237 performLeave()238 }239240 function performLeave() {241 // the delayed leave may have already been cancelled242 // @ts-expect-error243 if (cb.cancelled) {244 return245 }246 // record leaving element247 if (!vnode.data.show && el.parentNode) {248 ;(el.parentNode._pending || (el.parentNode._pending = {}))[vnode.key!] =249 vnode250 }251 beforeLeave && beforeLeave(el)252 if (expectsCSS) {253 addTransitionClass(el, leaveClass)254 addTransitionClass(el, leaveActiveClass)255 nextFrame(() => {256 removeTransitionClass(el, leaveClass)257 // @ts-expect-error258 if (!cb.cancelled) {259 addTransitionClass(el, leaveToClass)260 if (!userWantsControl) {261 if (isValidDuration(explicitLeaveDuration)) {262 setTimeout(cb, explicitLeaveDuration)263 } else {264 whenTransitionEnds(el, type, cb)265 }266 }267 }268 })269 }270 leave && leave(el, cb)271 if (!expectsCSS && !userWantsControl) {272 cb()273 }274 }275}276277// only used in dev mode278function checkDuration(val, name, vnode) {279 if (typeof val !== 'number') {280 warn(281 `<transition> explicit ${name} duration is not a valid number - ` +282 `got ${JSON.stringify(val)}.`,283 vnode.context284 )285 } else if (isNaN(val)) {286 warn(287 `<transition> explicit ${name} duration is NaN - ` +288 'the duration expression might be incorrect.',289 vnode.context290 )291 }292}293294function isValidDuration(val) {295 return typeof val === 'number' && !isNaN(val)296}297298/**299 * Normalize a transition hook's argument length. The hook may be:300 * - a merged hook (invoker) with the original in .fns301 * - a wrapped component method (check ._length)302 * - a plain function (.length)303 */304function getHookArgumentsLength(fn: Function): boolean {305 if (isUndef(fn)) {306 return false307 }308 // @ts-expect-error309 const invokerFns = fn.fns310 if (isDef(invokerFns)) {311 // invoker312 return getHookArgumentsLength(313 Array.isArray(invokerFns) ? invokerFns[0] : invokerFns314 )315 } else {316 // @ts-expect-error317 return (fn._length || fn.length) > 1318 }319}320321function _enter(_: any, vnode: VNodeWithData) {322 if (vnode.data.show !== true) {323 enter(vnode)324 }325}326327export default inBrowser328 ? {329 create: _enter,330 activate: _enter,331 remove(vnode: VNode, rm: Function) {332 /* istanbul ignore else */333 if (vnode.data!.show !== true) {334 // @ts-expect-error335 leave(vnode, rm)336 } else {337 rm()338 }339 }340 }341 : {}
Findings
✓ No findings reported for this file.