Browse Source

improve keep-alive: use component-based API

dev
Evan You 8 years ago
parent
commit
cdc0bc9cd4
  1. 1
      flow/compiler.js
  2. 4
      src/compiler/codegen/index.js
  3. 3
      src/compiler/parser/index.js
  4. 30
      src/core/components/keep-alive.js
  5. 11
      src/core/vdom/helpers.js
  6. 22
      src/platforms/web/runtime/components/transition.js
  7. 28
      test/unit/features/component/component-keep-alive.spec.js

1
flow/compiler.js

@ -82,7 +82,6 @@ declare type ASTElement = {
ns?: string;
component?: string;
keepAlive?: boolean;
inlineTemplate?: true;
transitionMode?: string | null;
slotName?: ?string;

4
src/compiler/codegen/index.js

@ -67,10 +67,6 @@ function genElement (el: ASTElement): string {
for (let i = 0; i < transforms.length; i++) {
code = transforms[i](el, code)
}
// check keep-alive
if (el.keepAlive) {
code = `_h("KeepAlive",{props:{child:${code}}})`
}
return code
}
}

3
src/compiler/parser/index.js

@ -345,9 +345,6 @@ function processComponent (el) {
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
}

30
src/core/components/keep-alive.js

@ -1,32 +1,30 @@
import { callHook } from 'core/instance/lifecycle'
import { getRealChild } from 'core/vdom/helpers'
import { getFirstComponentChild } from 'core/vdom/helpers'
export default {
name: 'keep-alive',
abstract: true,
props: {
child: Object
},
created () {
this.cache = Object.create(null)
},
render () {
const rawChild = this.child
const realChild = getRealChild(this.child)
if (realChild && realChild.componentOptions) {
const opts = realChild.componentOptions
// same constructor may get registered as different local components
// so cid alone is not enough (#3269)
const key = opts.Ctor.cid + '::' + opts.tag
const vnode = getFirstComponentChild(this.$slots.default)
if (vnode && vnode.componentOptions) {
const opts = vnode.componentOptions
const key = vnode.key == null
// same constructor may get registered as different local components
// so cid alone is not enough (#3269)
? opts.Ctor.cid + '::' + opts.tag
: vnode.key
if (this.cache[key]) {
const child = realChild.child = this.cache[key].child
realChild.elm = this.$el = child.$el
const child = vnode.child = this.cache[key].child
vnode.elm = this.$el = child.$el
} else {
this.cache[key] = realChild
this.cache[key] = vnode
}
realChild.data.keepAlive = true
vnode.data.keepAlive = true
}
return rawChild
return vnode
},
destroyed () {
for (const key in this.cache) {

11
src/core/vdom/helpers.js

@ -56,15 +56,8 @@ function applyNS (vnode, ns) {
}
}
// in case the child is also an abstract component, e.g. <transition-control>
// we want to recrusively retrieve the real component to be rendered
export function getRealChild (vnode: ?VNode): ?VNode {
const compOptions = vnode && vnode.componentOptions
if (compOptions && compOptions.Ctor.options.abstract) {
return getRealChild(compOptions.propsData && compOptions.propsData.child)
} else {
return vnode
}
export function getFirstComponentChild (children: ?Array<any>) {
return children && children.filter(c => c && c.componentOptions)[0]
}
export function mergeVNodeHook (def: Object, key: string, hook: Function) {

22
src/platforms/web/runtime/components/transition.js

@ -5,7 +5,7 @@
import { warn } from 'core/util/index'
import { camelize, extend } from 'shared/util'
import { getRealChild, mergeVNodeHook } from 'core/vdom/helpers'
import { mergeVNodeHook, getFirstComponentChild } from 'core/vdom/helpers'
export const transitionProps = {
name: String,
@ -21,6 +21,17 @@ export const transitionProps = {
appearActiveClass: String
}
// in case the child is also an abstract component, e.g. <keep-alive>
// we want to recrusively retrieve the real component to be rendered
function getRealChild (vnode: ?VNode): ?VNode {
const compOptions = vnode && vnode.componentOptions
if (compOptions && compOptions.Ctor.options.abstract) {
return getRealChild(getFirstComponentChild(compOptions.children))
} else {
return vnode
}
}
export function extractTransitionData (comp: Component): Object {
const data = {}
const options = comp.$options
@ -86,8 +97,13 @@ export default {
// use getRealChild() to ignore abstract components e.g. keep-alive
const child = getRealChild(rawChild)
/* istanbul ignore if */
if (!child) return
child.key = child.key || `__v${child.tag + this._uid}__`
if (!child) {
return rawChild
}
child.key = child.key == null
? `__v${child.tag + this._uid}__`
: child.key
const data = (child.data || (child.data = {})).transition = extractTransitionData(this)
const oldRawChild = this._vnode
const oldChild: any = getRealChild(oldRawChild)

28
test/unit/features/component/component-keep-alive.spec.js

@ -43,7 +43,13 @@ describe('Component keep-alive', () => {
it('should work', done => {
const vm = new Vue({
template: '<div v-if="ok"><component :is="view" keep-alive></component></div>',
template: `
<div v-if="ok">
<keep-alive>
<component :is="view"></component>
</keep-alive>
</div>
`,
data: {
view: 'one',
ok: true
@ -82,11 +88,9 @@ describe('Component keep-alive', () => {
const vm = new Vue({
template: `<div>
<transition name="test" mode="out-in" @after-leave="afterLeave">
<component
:is="view"
class="test"
keep-alive>
</component>
<keep-alive>
<component :is="view" class="test"></component>
</keep-alive>
<transition>
</div>`,
data: {
@ -169,11 +173,9 @@ describe('Component keep-alive', () => {
const vm = new Vue({
template: `<div>
<transition name="test" mode="in-out" @after-enter="afterEnter">
<component
:is="view"
class="test"
keep-alive>
</component>
<keep-alive>
<component :is="view" class="test"></component>
</keep-alive>
</transition>
</div>`,
data: {
@ -266,7 +268,9 @@ describe('Component keep-alive', () => {
const vm = new Vue({
template: `<div>
<transition name="test" mode="in-out" @after-enter="afterEnter">
<component :is="view" class="test" keep-alive></component>
<keep-alive>
<component :is="view" class="test"></component>
</keep-alive>
</transition>
</div>`,
data: { view: 'one' },

Loading…
Cancel
Save