mirror of https://github.com/vuejs/core.git
wip: refactor
This commit is contained in:
parent
61d6f4801b
commit
dccc47c265
|
@ -73,7 +73,7 @@ export interface KeepAliveContext extends ComponentRenderContext {
|
||||||
deactivate: (vnode: VNode) => void
|
deactivate: (vnode: VNode) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const isKeepAlive = (vnode: VNode): boolean =>
|
export const isKeepAlive = (vnode: any): boolean =>
|
||||||
(vnode.type as any).__isKeepAlive
|
(vnode.type as any).__isKeepAlive
|
||||||
|
|
||||||
const KeepAliveImpl: ComponentOptions = {
|
const KeepAliveImpl: ComponentOptions = {
|
||||||
|
@ -478,7 +478,7 @@ function injectToKeepAliveRoot(
|
||||||
}, target)
|
}, target)
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetShapeFlag(vnode: VNode) {
|
export function resetShapeFlag(vnode: any): void {
|
||||||
// bitwise operations to remove keep alive flags
|
// bitwise operations to remove keep alive flags
|
||||||
vnode.shapeFlag &= ~ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE
|
vnode.shapeFlag &= ~ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE
|
||||||
vnode.shapeFlag &= ~ShapeFlags.COMPONENT_KEPT_ALIVE
|
vnode.shapeFlag &= ~ShapeFlags.COMPONENT_KEPT_ALIVE
|
||||||
|
|
|
@ -564,7 +564,7 @@ export { getComponentName } from './component'
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
export { matches, isKeepAlive } from './components/KeepAlive'
|
export { matches, isKeepAlive, resetShapeFlag } from './components/KeepAlive'
|
||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -9,8 +9,8 @@ import {
|
||||||
} from 'vue'
|
} from 'vue'
|
||||||
import type { VaporComponent } from '../../src/component'
|
import type { VaporComponent } from '../../src/component'
|
||||||
import { makeRender } from '../_utils'
|
import { makeRender } from '../_utils'
|
||||||
|
import { VaporKeepAliveImpl as VaporKeepAlive } from '../../src/components/KeepAlive'
|
||||||
import {
|
import {
|
||||||
VaporKeepAlive,
|
|
||||||
child,
|
child,
|
||||||
createComponent,
|
createComponent,
|
||||||
createDynamicComponent,
|
createDynamicComponent,
|
||||||
|
@ -144,7 +144,7 @@ describe('VaporKeepAlive', () => {
|
||||||
const { mount } = define({
|
const { mount } = define({
|
||||||
setup() {
|
setup() {
|
||||||
const setTemplateRef = createTemplateRefSetter()
|
const setTemplateRef = createTemplateRefSetter()
|
||||||
const n4 = createComponent(VaporKeepAlive as any, null, {
|
const n4 = createComponent(VaporKeepAlive, null, {
|
||||||
default: () => {
|
default: () => {
|
||||||
const n0 = createDynamicComponent(() => views[viewRef.value]) as any
|
const n0 = createDynamicComponent(() => views[viewRef.value]) as any
|
||||||
setTemplateRef(n0, instanceRef)
|
setTemplateRef(n0, instanceRef)
|
||||||
|
@ -180,7 +180,7 @@ describe('VaporKeepAlive', () => {
|
||||||
return createIf(
|
return createIf(
|
||||||
() => toggle.value,
|
() => toggle.value,
|
||||||
() =>
|
() =>
|
||||||
createComponent(VaporKeepAlive as any, null, {
|
createComponent(VaporKeepAlive, null, {
|
||||||
default: () => createDynamicComponent(() => views[viewRef.value]),
|
default: () => createDynamicComponent(() => views[viewRef.value]),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
@ -235,7 +235,7 @@ describe('VaporKeepAlive', () => {
|
||||||
return createIf(
|
return createIf(
|
||||||
() => toggle.value,
|
() => toggle.value,
|
||||||
() =>
|
() =>
|
||||||
createComponent(VaporKeepAlive as any, null, {
|
createComponent(VaporKeepAlive, null, {
|
||||||
default: () => createDynamicComponent(() => views[viewRef.value]),
|
default: () => createDynamicComponent(() => views[viewRef.value]),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
@ -295,7 +295,7 @@ describe('VaporKeepAlive', () => {
|
||||||
const toggle = ref(true)
|
const toggle = ref(true)
|
||||||
const { html } = define({
|
const { html } = define({
|
||||||
setup() {
|
setup() {
|
||||||
return createComponent(VaporKeepAlive as any, null, {
|
return createComponent(VaporKeepAlive, null, {
|
||||||
default() {
|
default() {
|
||||||
return createIf(
|
return createIf(
|
||||||
() => toggle.value,
|
() => toggle.value,
|
||||||
|
@ -350,7 +350,7 @@ describe('VaporKeepAlive', () => {
|
||||||
const toggle = ref(true)
|
const toggle = ref(true)
|
||||||
const { html } = define({
|
const { html } = define({
|
||||||
setup() {
|
setup() {
|
||||||
return createComponent(VaporKeepAlive as any, null, {
|
return createComponent(VaporKeepAlive, null, {
|
||||||
default() {
|
default() {
|
||||||
return createIf(
|
return createIf(
|
||||||
() => toggle.value,
|
() => toggle.value,
|
||||||
|
@ -375,7 +375,7 @@ describe('VaporKeepAlive', () => {
|
||||||
onActivated(() => oneHooks.activated())
|
onActivated(() => oneHooks.activated())
|
||||||
onDeactivated(() => oneHooks.deactivated())
|
onDeactivated(() => oneHooks.deactivated())
|
||||||
onUnmounted(() => oneHooks.unmounted())
|
onUnmounted(() => oneHooks.unmounted())
|
||||||
return createComponent(VaporKeepAlive as any, null, {
|
return createComponent(VaporKeepAlive, null, {
|
||||||
default() {
|
default() {
|
||||||
return createIf(
|
return createIf(
|
||||||
() => toggle2.value,
|
() => toggle2.value,
|
||||||
|
@ -389,7 +389,7 @@ describe('VaporKeepAlive', () => {
|
||||||
const toggle1 = ref(true)
|
const toggle1 = ref(true)
|
||||||
const { html } = define({
|
const { html } = define({
|
||||||
setup() {
|
setup() {
|
||||||
return createComponent(VaporKeepAlive as any, null, {
|
return createComponent(VaporKeepAlive, null, {
|
||||||
default() {
|
default() {
|
||||||
return createIf(
|
return createIf(
|
||||||
() => toggle1.value,
|
() => toggle1.value,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { isArray } from '@vue/shared'
|
import { isArray } from '@vue/shared'
|
||||||
import {
|
import {
|
||||||
type VaporComponentInstance,
|
type VaporComponentInstance,
|
||||||
|
currentInstance,
|
||||||
isVaporComponent,
|
isVaporComponent,
|
||||||
mountComponent,
|
mountComponent,
|
||||||
unmountComponent,
|
unmountComponent,
|
||||||
|
@ -8,6 +9,8 @@ import {
|
||||||
import { createComment, createTextNode } from './dom/node'
|
import { createComment, createTextNode } from './dom/node'
|
||||||
import { EffectScope, pauseTracking, resetTracking } from '@vue/reactivity'
|
import { EffectScope, pauseTracking, resetTracking } from '@vue/reactivity'
|
||||||
import { isHydrating } from './dom/hydration'
|
import { isHydrating } from './dom/hydration'
|
||||||
|
import { isKeepAlive } from 'vue'
|
||||||
|
import type { KeepAliveInstance } from './components/KeepAlive'
|
||||||
|
|
||||||
export type Block =
|
export type Block =
|
||||||
| Node
|
| Node
|
||||||
|
@ -50,8 +53,14 @@ export class DynamicFragment extends VaporFragment {
|
||||||
pauseTracking()
|
pauseTracking()
|
||||||
const parent = this.anchor.parentNode
|
const parent = this.anchor.parentNode
|
||||||
|
|
||||||
|
const instance = currentInstance!
|
||||||
// teardown previous branch
|
// teardown previous branch
|
||||||
if (this.scope) {
|
if (this.scope) {
|
||||||
|
if (isKeepAlive(instance)) {
|
||||||
|
;(instance as KeepAliveInstance).process(
|
||||||
|
this.nodes as VaporComponentInstance,
|
||||||
|
)
|
||||||
|
}
|
||||||
this.scope.stop()
|
this.scope.stop()
|
||||||
parent && remove(this.nodes, parent)
|
parent && remove(this.nodes, parent)
|
||||||
}
|
}
|
||||||
|
@ -59,6 +68,11 @@ export class DynamicFragment extends VaporFragment {
|
||||||
if (render) {
|
if (render) {
|
||||||
this.scope = new EffectScope()
|
this.scope = new EffectScope()
|
||||||
this.nodes = this.scope.run(render) || []
|
this.nodes = this.scope.run(render) || []
|
||||||
|
if (isKeepAlive(instance)) {
|
||||||
|
;(instance as KeepAliveInstance).process(
|
||||||
|
this.nodes as VaporComponentInstance,
|
||||||
|
)
|
||||||
|
}
|
||||||
if (parent) insert(this.nodes, parent, this.anchor)
|
if (parent) insert(this.nodes, parent, this.anchor)
|
||||||
} else {
|
} else {
|
||||||
this.scope = undefined
|
this.scope = undefined
|
||||||
|
|
|
@ -15,7 +15,6 @@ import {
|
||||||
currentInstance,
|
currentInstance,
|
||||||
endMeasure,
|
endMeasure,
|
||||||
expose,
|
expose,
|
||||||
isKeepAlive,
|
|
||||||
nextUid,
|
nextUid,
|
||||||
popWarningContext,
|
popWarningContext,
|
||||||
pushWarningContext,
|
pushWarningContext,
|
||||||
|
@ -36,7 +35,13 @@ import {
|
||||||
resetTracking,
|
resetTracking,
|
||||||
unref,
|
unref,
|
||||||
} from '@vue/reactivity'
|
} from '@vue/reactivity'
|
||||||
import { EMPTY_OBJ, invokeArrayFns, isFunction, isString } from '@vue/shared'
|
import {
|
||||||
|
EMPTY_OBJ,
|
||||||
|
ShapeFlags,
|
||||||
|
invokeArrayFns,
|
||||||
|
isFunction,
|
||||||
|
isString,
|
||||||
|
} from '@vue/shared'
|
||||||
import {
|
import {
|
||||||
type DynamicPropsSource,
|
type DynamicPropsSource,
|
||||||
type RawProps,
|
type RawProps,
|
||||||
|
@ -376,6 +381,7 @@ export class VaporComponentInstance implements GenericComponentInstance {
|
||||||
propsOptions?: NormalizedPropsOptions
|
propsOptions?: NormalizedPropsOptions
|
||||||
emitsOptions?: ObjectEmitsOptions | null
|
emitsOptions?: ObjectEmitsOptions | null
|
||||||
isSingleRoot?: boolean
|
isSingleRoot?: boolean
|
||||||
|
shapeFlag?: number
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
comp: VaporComponent,
|
comp: VaporComponent,
|
||||||
|
@ -498,13 +504,12 @@ export function mountComponent(
|
||||||
parentNode: ParentNode,
|
parentNode: ParentNode,
|
||||||
anchor?: Node | null | 0,
|
anchor?: Node | null | 0,
|
||||||
): void {
|
): void {
|
||||||
let parent
|
if (instance.shapeFlag! & ShapeFlags.COMPONENT_KEPT_ALIVE) {
|
||||||
if (
|
;(instance.parent as KeepAliveInstance).activate(
|
||||||
(parent = instance.parent) &&
|
instance,
|
||||||
isKeepAlive(parent as any) &&
|
parentNode,
|
||||||
(parent as KeepAliveInstance).isKeptAlive(instance)
|
anchor as any,
|
||||||
) {
|
)
|
||||||
;(parent as KeepAliveInstance).activate(instance, parentNode, anchor as any)
|
|
||||||
instance.isMounted = true
|
instance.isMounted = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -516,9 +521,7 @@ export function mountComponent(
|
||||||
insert(instance.block, parentNode, anchor)
|
insert(instance.block, parentNode, anchor)
|
||||||
if (instance.m) queuePostFlushCb(() => invokeArrayFns(instance.m!))
|
if (instance.m) queuePostFlushCb(() => invokeArrayFns(instance.m!))
|
||||||
if (
|
if (
|
||||||
parent &&
|
instance.shapeFlag! & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE &&
|
||||||
isKeepAlive(parent as any) &&
|
|
||||||
(parent as KeepAliveInstance).shouldKeepAlive(instance) &&
|
|
||||||
instance.a
|
instance.a
|
||||||
) {
|
) {
|
||||||
queuePostFlushCb(instance.a!)
|
queuePostFlushCb(instance.a!)
|
||||||
|
@ -533,13 +536,8 @@ export function unmountComponent(
|
||||||
instance: VaporComponentInstance,
|
instance: VaporComponentInstance,
|
||||||
parentNode?: ParentNode,
|
parentNode?: ParentNode,
|
||||||
): void {
|
): void {
|
||||||
let parent
|
if (instance.shapeFlag! & ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE) {
|
||||||
if (
|
;(instance.parent as KeepAliveInstance).deactivate(instance)
|
||||||
(parent = instance.parent) &&
|
|
||||||
isKeepAlive(parent as any) &&
|
|
||||||
(parent as KeepAliveInstance).shouldKeepAlive(instance)
|
|
||||||
) {
|
|
||||||
;(parent as KeepAliveInstance).deactivate(instance)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,25 +3,25 @@ import {
|
||||||
currentInstance,
|
currentInstance,
|
||||||
devtoolsComponentAdded,
|
devtoolsComponentAdded,
|
||||||
getComponentName,
|
getComponentName,
|
||||||
invalidateMount,
|
|
||||||
isKeepAlive,
|
|
||||||
matches,
|
matches,
|
||||||
onBeforeUnmount,
|
onBeforeUnmount,
|
||||||
onMounted,
|
onMounted,
|
||||||
onUpdated,
|
onUpdated,
|
||||||
queuePostFlushCb,
|
queuePostFlushCb,
|
||||||
|
resetShapeFlag,
|
||||||
warn,
|
warn,
|
||||||
watch,
|
watch,
|
||||||
} from '@vue/runtime-dom'
|
} from '@vue/runtime-dom'
|
||||||
import { type Block, insert, isFragment, isValidBlock } from '../block'
|
import { type Block, insert, isFragment, isValidBlock } from '../block'
|
||||||
import {
|
import {
|
||||||
|
type ObjectVaporComponent,
|
||||||
type VaporComponent,
|
type VaporComponent,
|
||||||
type VaporComponentInstance,
|
type VaporComponentInstance,
|
||||||
isVaporComponent,
|
isVaporComponent,
|
||||||
unmountComponent,
|
unmountComponent,
|
||||||
} from '../component'
|
} from '../component'
|
||||||
import { defineVaporComponent } from '../apiDefineComponent'
|
import { defineVaporComponent } from '../apiDefineComponent'
|
||||||
import { invokeArrayFns, isArray } from '@vue/shared'
|
import { ShapeFlags, invokeArrayFns, isArray } from '@vue/shared'
|
||||||
|
|
||||||
export interface KeepAliveInstance extends VaporComponentInstance {
|
export interface KeepAliveInstance extends VaporComponentInstance {
|
||||||
activate: (
|
activate: (
|
||||||
|
@ -30,15 +30,14 @@ export interface KeepAliveInstance extends VaporComponentInstance {
|
||||||
anchor: Node,
|
anchor: Node,
|
||||||
) => void
|
) => void
|
||||||
deactivate: (instance: VaporComponentInstance) => void
|
deactivate: (instance: VaporComponentInstance) => void
|
||||||
shouldKeepAlive: (instance: VaporComponentInstance) => boolean
|
process: (instance: VaporComponentInstance) => void
|
||||||
isKeptAlive: (instance: VaporComponentInstance) => boolean
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type CacheKey = PropertyKey | VaporComponent
|
type CacheKey = PropertyKey | VaporComponent
|
||||||
type Cache = Map<CacheKey, VaporComponentInstance>
|
type Cache = Map<CacheKey, VaporComponentInstance>
|
||||||
type Keys = Set<CacheKey>
|
type Keys = Set<CacheKey>
|
||||||
|
|
||||||
const VaporKeepAliveImpl = defineVaporComponent({
|
export const VaporKeepAliveImpl: ObjectVaporComponent = defineVaporComponent({
|
||||||
name: 'VaporKeepAlive',
|
name: 'VaporKeepAlive',
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
__isKeepAlive: true,
|
__isKeepAlive: true,
|
||||||
|
@ -57,7 +56,6 @@ const VaporKeepAliveImpl = defineVaporComponent({
|
||||||
const keys: Keys = new Set()
|
const keys: Keys = new Set()
|
||||||
const storageContainer = document.createElement('div')
|
const storageContainer = document.createElement('div')
|
||||||
let current: VaporComponentInstance | undefined
|
let current: VaporComponentInstance | undefined
|
||||||
let isUnmounting = false
|
|
||||||
|
|
||||||
if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
|
if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
|
||||||
;(keepAliveInstance as any).__v_cache = cache
|
;(keepAliveInstance as any).__v_cache = cache
|
||||||
|
@ -90,9 +88,10 @@ const VaporKeepAliveImpl = defineVaporComponent({
|
||||||
|
|
||||||
onMounted(cacheBlock)
|
onMounted(cacheBlock)
|
||||||
onUpdated(cacheBlock)
|
onUpdated(cacheBlock)
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
isUnmounting = true
|
|
||||||
cache.forEach(cached => {
|
cache.forEach(cached => {
|
||||||
|
resetShapeFlag(cached)
|
||||||
cache.delete(cached.type)
|
cache.delete(cached.type)
|
||||||
// current instance will be unmounted as part of keep-alive's unmount
|
// current instance will be unmounted as part of keep-alive's unmount
|
||||||
if (current && current.type === cached.type) {
|
if (current && current.type === cached.type) {
|
||||||
|
@ -104,12 +103,20 @@ const VaporKeepAliveImpl = defineVaporComponent({
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const children = slots.default()
|
keepAliveInstance.process = (instance: VaporComponentInstance) => {
|
||||||
if (isArray(children) && children.length > 1) {
|
if (cache.has(instance.type)) {
|
||||||
if (__DEV__) {
|
instance.shapeFlag! |= ShapeFlags.COMPONENT_KEPT_ALIVE
|
||||||
warn(`KeepAlive should contain exactly one component child.`)
|
}
|
||||||
|
|
||||||
|
const name = getComponentName(instance.type)
|
||||||
|
if (
|
||||||
|
!(
|
||||||
|
(include && (!name || !matches(include, name))) ||
|
||||||
|
(exclude && name && matches(exclude, name))
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
instance.shapeFlag! |= ShapeFlags.COMPONENT_SHOULD_KEEP_ALIVE
|
||||||
}
|
}
|
||||||
return children
|
|
||||||
}
|
}
|
||||||
|
|
||||||
keepAliveInstance.activate = (
|
keepAliveInstance.activate = (
|
||||||
|
@ -117,9 +124,6 @@ const VaporKeepAliveImpl = defineVaporComponent({
|
||||||
parentNode: ParentNode,
|
parentNode: ParentNode,
|
||||||
anchor: Node,
|
anchor: Node,
|
||||||
) => {
|
) => {
|
||||||
// invalidateMount(instance.m)
|
|
||||||
// invalidateMount(instance.a)
|
|
||||||
|
|
||||||
const cachedBlock = cache.get(instance.type)!
|
const cachedBlock = cache.get(instance.type)!
|
||||||
insert((instance.block = cachedBlock.block), parentNode, anchor)
|
insert((instance.block = cachedBlock.block), parentNode, anchor)
|
||||||
queuePostFlushCb(() => {
|
queuePostFlushCb(() => {
|
||||||
|
@ -144,20 +148,12 @@ const VaporKeepAliveImpl = defineVaporComponent({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
keepAliveInstance.shouldKeepAlive = (instance: VaporComponentInstance) => {
|
const children = slots.default()
|
||||||
if (isUnmounting) return false
|
if (isArray(children) && children.length > 1) {
|
||||||
const name = getComponentName(instance.type)
|
if (__DEV__) {
|
||||||
if (
|
warn(`KeepAlive should contain exactly one component child.`)
|
||||||
(include && (!name || !matches(include, name))) ||
|
|
||||||
(exclude && name && matches(exclude, name))
|
|
||||||
) {
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
return true
|
return children
|
||||||
}
|
|
||||||
|
|
||||||
keepAliveInstance.isKeptAlive = (instance: VaporComponentInstance) => {
|
|
||||||
return cache.has(instance.type)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function pruneCache(filter: (name: string) => boolean) {
|
function pruneCache(filter: (name: string) => boolean) {
|
||||||
|
|
Loading…
Reference in New Issue