mirror of
https://gitee.com/vuejs/vue.git
synced 2024-12-02 12:07:39 +08:00
transition-mode
This commit is contained in:
parent
8015100d77
commit
7a3261115f
@ -15,8 +15,9 @@ declare type CompilerOptions = {
|
||||
|
||||
declare type ModuleOptions = {
|
||||
staticKeys?: Array<string>,
|
||||
parse: Function,
|
||||
genData: Function
|
||||
parse: (el: ASTElement) => void,
|
||||
genData: (el: ASTElement) => string,
|
||||
transformElement?: (el: ASTElement, code: string) => string
|
||||
}
|
||||
|
||||
declare type ASTElementHandler = {
|
||||
@ -59,7 +60,9 @@ declare type ASTElement = {
|
||||
ns?: string,
|
||||
|
||||
component?: string,
|
||||
keepAlive?: boolean,
|
||||
inlineTemplate?: true,
|
||||
transitionMode?: string | null,
|
||||
slotName?: ?string,
|
||||
slotTarget?: ?string,
|
||||
|
||||
|
@ -47,29 +47,39 @@ function genElement (el: ASTElement): string {
|
||||
return genRender(el)
|
||||
} else if (el.tag === 'slot') {
|
||||
return genSlot(el)
|
||||
} else if (el.component) {
|
||||
return genComponent(el)
|
||||
} else {
|
||||
const data = genData(el)
|
||||
// if the element is potentially a component,
|
||||
// wrap its children as a thunk.
|
||||
const children = !el.inlineTemplate
|
||||
? genChildren(el, !el.ns && !isPlatformReservedTag(el.tag) /* asThunk */)
|
||||
: null
|
||||
const code = `_h(_e('${el.tag}'${
|
||||
data ? `,${data}` : el.ns ? ',void 0' : '' // data
|
||||
}${
|
||||
el.ns ? `,'${el.ns}'` : '' // namespace
|
||||
})${
|
||||
children ? `,${children}` : '' // children
|
||||
})`
|
||||
if (el.staticRoot) {
|
||||
// hoist static sub-trees out
|
||||
staticRenderFns.push(`with(this){return ${code}}`)
|
||||
return `_m(${staticRenderFns.length - 1})`
|
||||
// component or element
|
||||
let code
|
||||
if (el.component) {
|
||||
code = genComponent(el)
|
||||
} else {
|
||||
return code
|
||||
const data = genData(el)
|
||||
// if the element is potentially a component,
|
||||
// wrap its children as a thunk.
|
||||
const children = !el.inlineTemplate
|
||||
? genChildren(el, !el.ns && !isPlatformReservedTag(el.tag) /* asThunk */)
|
||||
: null
|
||||
code = `_h(_e('${el.tag}'${
|
||||
data ? `,${data}` : el.ns ? ',void 0' : '' // data
|
||||
}${
|
||||
el.ns ? `,'${el.ns}'` : '' // namespace
|
||||
})${
|
||||
children ? `,${children}` : '' // children
|
||||
})`
|
||||
if (el.staticRoot) {
|
||||
// hoist static sub-trees out
|
||||
staticRenderFns.push(`with(this){return ${code}}`)
|
||||
code = `_m(${staticRenderFns.length - 1})`
|
||||
}
|
||||
}
|
||||
// platform modules
|
||||
for (let i = 0; i < platformModules.length; i++) {
|
||||
const transform = platformModules[i].transformElement
|
||||
if (transform) {
|
||||
code = transform(el, code)
|
||||
}
|
||||
}
|
||||
return code
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -313,9 +313,12 @@ function processSlot (el) {
|
||||
}
|
||||
|
||||
function processComponent (el) {
|
||||
const isBinding = getBindingAttr(el, 'is')
|
||||
if (isBinding) {
|
||||
el.component = isBinding
|
||||
let binding
|
||||
if ((binding = getBindingAttr(el, 'is'))) {
|
||||
el.component = binding
|
||||
}
|
||||
if (getAndRemoveAttr(el, 'keep-alive') != null) {
|
||||
el.keepAlive = true
|
||||
}
|
||||
if (getAndRemoveAttr(el, 'inline-template') != null) {
|
||||
el.inlineTemplate = true
|
||||
|
@ -2,9 +2,10 @@
|
||||
|
||||
import Vue from 'core/index'
|
||||
import config from 'core/config'
|
||||
import { noop } from 'shared/util'
|
||||
import { extend, noop } from 'shared/util'
|
||||
import { patch } from 'web/runtime/patch'
|
||||
import platformDirectives from 'web/runtime/directives/index'
|
||||
import platformComponents from 'web/runtime/components/index'
|
||||
import { query, isUnknownElement, isReservedTag, mustUseProp } from 'web/util/index'
|
||||
|
||||
// install platform specific utils
|
||||
@ -12,8 +13,9 @@ Vue.config.isUnknownElement = isUnknownElement
|
||||
Vue.config.isReservedTag = isReservedTag
|
||||
Vue.config.mustUseProp = mustUseProp
|
||||
|
||||
// install platform runtime directives
|
||||
Vue.options.directives = platformDirectives
|
||||
// install platform runtime directives & components
|
||||
extend(Vue.options.directives, platformDirectives)
|
||||
extend(Vue.options.components, platformComponents)
|
||||
|
||||
// install platform patch function
|
||||
Vue.prototype.__patch__ = config._isServer ? noop : patch
|
||||
|
@ -12,6 +12,10 @@ function parse (el: ASTElement) {
|
||||
if (transition) {
|
||||
el.transition = transition
|
||||
}
|
||||
const mode = getBindingAttr(el, 'transition-mode')
|
||||
if (mode) {
|
||||
el.transitionMode = mode
|
||||
}
|
||||
}
|
||||
|
||||
function genData (el: ASTElement): string {
|
||||
@ -20,7 +24,16 @@ function genData (el: ASTElement): string {
|
||||
: ''
|
||||
}
|
||||
|
||||
function transformElement (el: ASTElement, code: string): string {
|
||||
return el.transitionMode
|
||||
? `_h(_e('transition-control',{props:{mode:${
|
||||
el.transitionMode
|
||||
}}}),function(){return [${code}]})`
|
||||
: code
|
||||
}
|
||||
|
||||
export default {
|
||||
parse,
|
||||
genData
|
||||
genData,
|
||||
transformElement
|
||||
}
|
||||
|
5
src/platforms/web/runtime/components/index.js
Normal file
5
src/platforms/web/runtime/components/index.js
Normal file
@ -0,0 +1,5 @@
|
||||
import transitionControl from './transition-control'
|
||||
|
||||
export default {
|
||||
transitionControl
|
||||
}
|
66
src/platforms/web/runtime/components/transition-control.js
Normal file
66
src/platforms/web/runtime/components/transition-control.js
Normal file
@ -0,0 +1,66 @@
|
||||
/* flow */
|
||||
|
||||
import { warn } from 'core/util/index'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
mode: {
|
||||
validator (val) {
|
||||
if (val && val !== 'out-in' && val !== 'in-out') {
|
||||
warn('transition-mode must be either "out-in" or "in-out".')
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
},
|
||||
render () {
|
||||
const oldChild = this._vnode
|
||||
const newChild = this.$slots.default[0]
|
||||
if (oldChild && oldChild.data && oldChild.tag !== newChild.tag) {
|
||||
if (this.mode === 'out-in') {
|
||||
// return empty node
|
||||
// and queue an update when the leave finishes
|
||||
addHook(oldChild, 'afterLeave', () => {
|
||||
this.$forceUpdate()
|
||||
})
|
||||
return
|
||||
} else {
|
||||
if (this.mode === 'in-out') {
|
||||
let delayedLeave
|
||||
const performLeave = () => { delayedLeave() }
|
||||
addHook(newChild, 'afterEnter', performLeave)
|
||||
addHook(newChild, 'enterCancelled', performLeave)
|
||||
addHook(oldChild, 'delayLeave', leave => {
|
||||
delayedLeave = leave
|
||||
})
|
||||
}
|
||||
return newChild
|
||||
}
|
||||
} else {
|
||||
return newChild
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addHook (vnode: VNode, name: string, hook: Function) {
|
||||
if (!vnode.data || !vnode.data.transition) {
|
||||
return
|
||||
}
|
||||
let trans = vnode.data.transition
|
||||
if (typeof trans === 'string') {
|
||||
trans = vnode.data.transition = { name: trans }
|
||||
} else if (typeof trans !== 'object') {
|
||||
trans = vnode.data.transition = { name: 'v' }
|
||||
}
|
||||
if (trans[name]) {
|
||||
const oldHook = trans[name]
|
||||
trans[name] = function (el) {
|
||||
const res = oldHook.apply(this, arguments)
|
||||
hook()
|
||||
return res
|
||||
}
|
||||
} else {
|
||||
trans[name] = hook
|
||||
}
|
||||
}
|
@ -129,7 +129,8 @@ export function leave (vnode: VNodeWithData, rm: Function) {
|
||||
beforeLeave,
|
||||
onLeave,
|
||||
afterLeave,
|
||||
leaveCancelled
|
||||
leaveCancelled,
|
||||
delayLeave
|
||||
} = resolveTransition(data, vnode.context)
|
||||
|
||||
const expectsCSS = css !== false
|
||||
@ -150,22 +151,30 @@ export function leave (vnode: VNodeWithData, rm: Function) {
|
||||
el._leaveCb = null
|
||||
})
|
||||
|
||||
beforeLeave && beforeLeave(el)
|
||||
if (expectsCSS) {
|
||||
addTransitionClass(el, leaveClass)
|
||||
nextFrame(() => {
|
||||
removeTransitionClass(el, leaveClass)
|
||||
if (!cb.cancelled) {
|
||||
addTransitionClass(el, leaveActiveClass)
|
||||
if (!userWantsControl) {
|
||||
whenTransitionEnds(el, cb)
|
||||
}
|
||||
}
|
||||
})
|
||||
if (delayLeave) {
|
||||
delayLeave(performLeave)
|
||||
} else {
|
||||
performLeave()
|
||||
}
|
||||
onLeave && onLeave(el, cb)
|
||||
if (!expectsCSS && !userWantsControl) {
|
||||
cb()
|
||||
|
||||
function performLeave () {
|
||||
beforeLeave && beforeLeave(el)
|
||||
if (expectsCSS) {
|
||||
addTransitionClass(el, leaveClass)
|
||||
nextFrame(() => {
|
||||
removeTransitionClass(el, leaveClass)
|
||||
if (!cb.cancelled) {
|
||||
addTransitionClass(el, leaveActiveClass)
|
||||
if (!userWantsControl) {
|
||||
whenTransitionEnds(el, cb)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
onLeave && onLeave(el, cb)
|
||||
if (!expectsCSS && !userWantsControl) {
|
||||
cb()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user