transition wip

This commit is contained in:
Evan You 2016-04-19 17:26:24 -04:00
parent 79e164084b
commit 52ac04d235
9 changed files with 167 additions and 33 deletions

View File

@ -92,8 +92,8 @@ function genData (el) {
data += `style:${el.styleBinding},`
}
// transition
if (el.transition) {
data += `transition:${el.transition},`
if (el.transition != null) {
data += `transition:__resolveTransition__(${el.transition}),`
}
// props
if (el.props) {

View File

@ -49,7 +49,7 @@ export function addHandler (el, name, value, modifiers) {
export function getBindingAttr (el, name, getStatic) {
const staticValue = getStatic !== false && getAndRemoveAttr(el, name)
return staticValue
return staticValue || staticValue === ''
? JSON.stringify(staticValue)
: (getAndRemoveAttr(el, ':' + name) || getAndRemoveAttr(el, 'v-bind:' + name))
}

View File

@ -0,0 +1,79 @@
import { isIE9 } from '../util/index'
import { svgNS } from './node-ops'
/**
* In IE9, setAttribute('class') will result in empty class
* if the element also has the :class attribute; However in
* PhantomJS, setting `className` does not work on SVG elements...
* So we have to do a conditional check here.
*
* @param {Element} el
* @param {String} cls
*/
export function setClass (el, cls) {
/* istanbul ignore else */
if (!isIE9 || el.namespaceURI === svgNS) {
el.setAttribute('class', cls)
} else {
el.className = cls
}
}
/**
* Add class with compatibility for IE & SVG
*
* @param {Element} el
* @param {String} cls
*/
export function addClass (el, cls) {
if (el.classList) {
el.classList.add(cls)
} else {
let cur = ' ' + getClass(el) + ' '
if (cur.indexOf(' ' + cls + ' ') < 0) {
setClass(el, (cur + cls).trim())
}
}
}
/**
* Remove class with compatibility for IE & SVG
*
* @param {Element} el
* @param {String} cls
*/
export function removeClass (el, cls) {
if (el.classList) {
el.classList.remove(cls)
} else {
let cur = ' ' + getClass(el) + ' '
let tar = ' ' + cls + ' '
while (cur.indexOf(tar) >= 0) {
cur = cur.replace(tar, ' ')
}
setClass(el, cur.trim())
}
if (!el.className) {
el.removeAttribute('class')
}
}
/**
* For IE9 compat: when both class and :class are present
* getAttribute('class') returns wrong value... but className
* on SVG elements returns an object.
*
* @param {Element} el
* @return {String}
*/
function getClass (el) {
var classname = el.className
if (typeof classname === 'object') {
classname = classname.baseVal || ''
}
return classname
}

View File

@ -6,6 +6,7 @@ import props from './modules/props'
import attrs from './modules/attrs'
import events from './modules/events'
import directives from './modules/directives'
import transition from './modules/transition'
export const patch = createPatchFunction({
nodeOps,
@ -15,6 +16,7 @@ export const patch = createPatchFunction({
attrs,
style,
events,
directives
directives,
transition
]
})

View File

@ -1,20 +1,25 @@
import { isIE9, isArray, isObject } from '../../util/index'
import { isArray, isObject } from '../../util/index'
import { setClass } from '../class-util'
function updateClass (oldVnode, vnode) {
let dynamicClass = vnode.data.class
let staticClass = vnode.data.staticClass
if (staticClass || dynamicClass) {
const el = vnode.elm
const activeClass = el._activeClass
if (staticClass || dynamicClass || activeClass) {
dynamicClass = genClass(dynamicClass)
let cls = staticClass
? staticClass + (dynamicClass ? ' ' + dynamicClass : '')
: dynamicClass
const cls = concatClass(concatClass(staticClass, dynamicClass), activeClass)
if (cls !== oldVnode.class) {
setClass(vnode.elm, cls)
setClass(el, cls)
}
vnode.class = cls
}
}
function concatClass (a, b) {
return a ? b ? (a + ' ' + b) : a : (b || '')
}
function genClass (data) {
if (!data) {
return ''
@ -38,25 +43,6 @@ function genClass (data) {
}
}
/**
* In IE9, setAttribute('class') will result in empty class
* if the element also has the :class attribute; However in
* PhantomJS, setting `className` does not work on SVG elements...
* So we have to do a conditional check here.
*
* @param {Element} el
* @param {String} cls
*/
export function setClass (el, cls) {
/* istanbul ignore if */
if (isIE9 && !/svg$/.test(el.namespaceURI)) {
el.className = cls
} else {
el.setAttribute('class', cls)
}
}
export default {
create: updateClass,
update: updateClass

View File

@ -1,11 +1,11 @@
export default {
create: function (oldVnode, vnode) {
create: function bindDirectives (oldVnode, vnode) {
applyDirectives(oldVnode, vnode, 'bind')
},
update: function (oldVnode, vnode) {
update: function updateDirectives (oldVnode, vnode) {
applyDirectives(oldVnode, vnode, 'update', true)
},
destroy: function (vnode) {
destroy: function unbindDirectives (vnode) {
applyDirectives(null, vnode, 'unbind')
}
}

View File

@ -0,0 +1,60 @@
import { addClass, removeClass } from '../class-util'
import {
isIE9,
inBrowser,
transitionProp,
transitionEndEvent,
animationProp,
animationEndEvent
} from '../../util/index'
export default isIE9 ? {} : {
create: function applyEnterTransition (_, vnode) {
let data = vnode.data.transition
const el = vnode.elm
if (data != null) {
if (typeof data === 'string') {
// pure CSS
data = cssTransition(data)
}
// apply enter class
const enterClass = data.enterClass
if (enterClass) {
addClass(el, enterClass)
nextFrame(() => {
removeClass(el, enterClass)
})
}
const enterActiveClass = data.enterActiveClass
if (enterActiveClass) {
el._activeClass = enterActiveClass
addClass(el, enterActiveClass)
el.addEventListener(transitionEndEvent, () => {
el._activeClass = null
removeClass(el, enterActiveClass)
})
}
}
},
remove: function applyLeaveTransition (vnode, rm) {
}
}
const raf = (inBrowser && window.requestAnimationFrame) || setTimeout
function nextFrame (fn) {
raf(() => {
raf(fn)
})
}
function cssTransition (name) {
name = name || 'v'
return {
enterClass: `${name}-enter`,
leaveClass: `${name}-leave`,
enterActiveClass: `${name}-enter-active`,
leaveActiveClass: `${name}-leave-active`
}
}

View File

@ -1,4 +1,4 @@
const svgNS = 'http://www.w3.org/2000/svg'
export const svgNS = 'http://www.w3.org/2000/svg'
export function createElement (tagName) {
return document.createElement(tagName)

View File

@ -34,6 +34,13 @@ export function renderMixin (Vue) {
return resolveAsset(this.$options, 'directives', id, true)
}
// resolve transition
Vue.prototype.__resolveTransition__ = function (id) {
return id && typeof id === 'string'
? resolveAsset(this.$options, 'transitions', id) || id
: id
}
// toString for mustaches
Vue.prototype.__toString__ = function (val) {
return val == null