src/core/components/keep-alive.ts TYPESCRIPT 172 lines View on github.com → Search inside
1import { isRegExp, isArray, remove } from 'shared/util'2import { getFirstComponentChild } from 'core/vdom/helpers/index'3import type VNode from 'core/vdom/vnode'4import type { VNodeComponentOptions } from 'types/vnode'5import type { Component } from 'types/component'6import { getComponentName } from '../vdom/create-component'78type CacheEntry = {9  name?: string10  tag?: string11  componentInstance?: Component12}1314type CacheEntryMap = Record<string, CacheEntry | null>1516function _getComponentName(opts?: VNodeComponentOptions): string | null {17  return opts && (getComponentName(opts.Ctor.options as any) || opts.tag)18}1920function matches(21  pattern: string | RegExp | Array<string>,22  name: string23): boolean {24  if (isArray(pattern)) {25    return pattern.indexOf(name) > -126  } else if (typeof pattern === 'string') {27    return pattern.split(',').indexOf(name) > -128  } else if (isRegExp(pattern)) {29    return pattern.test(name)30  }31  /* istanbul ignore next */32  return false33}3435function pruneCache(36  keepAliveInstance: {37    cache: CacheEntryMap38    keys: string[]39    _vnode: VNode40    $vnode: VNode41  },42  filter: Function43) {44  const { cache, keys, _vnode, $vnode } = keepAliveInstance45  for (const key in cache) {46    const entry = cache[key]47    if (entry) {48      const name = entry.name49      if (name && !filter(name)) {50        pruneCacheEntry(cache, key, keys, _vnode)51      }52    }53  }54  $vnode.componentOptions!.children = undefined55}5657function pruneCacheEntry(58  cache: CacheEntryMap,59  key: string,60  keys: Array<string>,61  current?: VNode62) {63  const entry = cache[key]64  if (entry && (!current || entry.tag !== current.tag)) {65    // @ts-expect-error can be undefined66    entry.componentInstance.$destroy()67  }68  cache[key] = null69  remove(keys, key)70}7172const patternTypes: Array<Function> = [String, RegExp, Array]7374// TODO defineComponent75export default {76  name: 'keep-alive',77  abstract: true,7879  props: {80    include: patternTypes,81    exclude: patternTypes,82    max: [String, Number]83  },8485  methods: {86    cacheVNode() {87      const { cache, keys, vnodeToCache, keyToCache } = this88      if (vnodeToCache) {89        const { tag, componentInstance, componentOptions } = vnodeToCache90        cache[keyToCache] = {91          name: _getComponentName(componentOptions),92          tag,93          componentInstance94        }95        keys.push(keyToCache)96        // prune oldest entry97        if (this.max && keys.length > parseInt(this.max)) {98          pruneCacheEntry(cache, keys[0], keys, this._vnode)99        }100        this.vnodeToCache = null101      }102    }103  },104105  created() {106    this.cache = Object.create(null)107    this.keys = []108  },109110  destroyed() {111    for (const key in this.cache) {112      pruneCacheEntry(this.cache, key, this.keys)113    }114  },115116  mounted() {117    this.cacheVNode()118    this.$watch('include', val => {119      pruneCache(this, name => matches(val, name))120    })121    this.$watch('exclude', val => {122      pruneCache(this, name => !matches(val, name))123    })124  },125126  updated() {127    this.cacheVNode()128  },129130  render() {131    const slot = this.$slots.default132    const vnode = getFirstComponentChild(slot)133    const componentOptions = vnode && vnode.componentOptions134    if (componentOptions) {135      // check pattern136      const name = _getComponentName(componentOptions)137      const { include, exclude } = this138      if (139        // not included140        (include && (!name || !matches(include, name))) ||141        // excluded142        (exclude && name && matches(exclude, name))143      ) {144        return vnode145      }146147      const { cache, keys } = this148      const key =149        vnode.key == null150          ? // same constructor may get registered as different local components151            // so cid alone is not enough (#3269)152            componentOptions.Ctor.cid +153            (componentOptions.tag ? `::${componentOptions.tag}` : '')154          : vnode.key155      if (cache[key]) {156        vnode.componentInstance = cache[key].componentInstance157        // make current key freshest158        remove(keys, key)159        keys.push(key)160      } else {161        // delay setting the cache until update162        this.vnodeToCache = vnode163        this.keyToCache = key164      }165166      // @ts-expect-error can vnode.data can be undefined167      vnode.data.keepAlive = true168    }169    return vnode || (slot && slot[0])170  }171}

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.