Explorar o código

ensure abstract HOCs do not alter parent chain

Evan You %!s(int64=10) %!d(string=hai) anos
pai
achega
cb67ffe442

+ 1 - 0
flow/component.js

@@ -47,6 +47,7 @@ declare interface Component {
   _isVue: true;
   _self: Component;
   _renderProxy: Component;
+  _renderParent: ?Component;
   _watcher: Watcher;
   _watchers: Array<Watcher>;
   _data: Object;

+ 2 - 0
src/core/components/keep-alive.js

@@ -1,4 +1,6 @@
 export default {
+  name: 'keep-alive',
+  _abstract: true,
   created () {
     this.cache = Object.create(null)
   },

+ 2 - 2
src/core/instance/lifecycle.js

@@ -10,7 +10,7 @@ export function initLifecycle (vm: Component) {
 
   vm.$parent = options.parent
   vm.$root = vm.$parent ? vm.$parent.$root : vm
-  if (vm.$parent) {
+  if (vm.$parent && !options._abstract) {
     vm.$parent.$children.push(vm)
   }
 
@@ -145,7 +145,7 @@ export function lifecycleMixin (Vue: Class<Component>) {
     vm._isBeingDestroyed = true
     // remove self from parent
     const parent = vm.$parent
-    if (parent && !parent._isBeingDestroyed) {
+    if (parent && !parent._isBeingDestroyed && !vm.$options._abstract) {
       remove(parent.$children, vm)
     }
     // teardown watchers

+ 15 - 2
src/core/instance/render.js

@@ -16,7 +16,7 @@ import {
 } from '../vdom/create-element'
 
 export const renderState: {
-  activeInstance: Component | null
+  activeInstance: ?Component
 } = {
   activeInstance: null
 }
@@ -35,6 +35,19 @@ export function initRender (vm: Component) {
   ) {
     return this._h(this._e(tag, data, namespace), children)
   }, vm)
+  // for abstract components, determine first non-abstract parent
+  // so that the children of abstract components are considered children
+  // of the first non-abstract parent.
+  // this is used by internal abstract components like <keep-alive>.
+  if (vm.$options._abstract) {
+    let parent = vm.$parent
+    while (parent && parent.$options._abstract) {
+      parent = parent.$parent
+    }
+    vm._renderParent = parent
+  } else {
+    vm._renderParent = vm
+  }
   if (vm.$options.el) {
     vm.$mount(vm.$options.el)
   }
@@ -48,7 +61,7 @@ export function renderMixin (Vue: Class<Component>) {
   Vue.prototype._render = function (): VNode {
     const vm: Component = this
     const prev = renderState.activeInstance
-    renderState.activeInstance = vm
+    renderState.activeInstance = vm._renderParent
     if (!vm._isMounted) {
       // render static sub-trees for once on initial render
       renderStaticTrees(vm)

+ 1 - 1
src/core/util/env.js

@@ -15,7 +15,7 @@ export const devtools = inBrowser && window.__VUE_DEVTOOLS_GLOBAL_HOOK__
 // UA sniffing for working around browser-specific quirks
 const UA = inBrowser && window.navigator.userAgent.toLowerCase()
 const isIos = UA && /(iphone|ipad|ipod|ios)/i.test(UA)
-const iosVersionMatch = isIos && UA.match(/os ([\d_]+)/)
+const iosVersionMatch = UA && isIos && UA.match(/os ([\d_]+)/)
 const iosVersion = iosVersionMatch && iosVersionMatch[1].split('_')
 
 // MutationObserver is unreliable in iOS 9.3 UIWebView

+ 1 - 1
src/core/vdom/create-element.js

@@ -36,7 +36,7 @@ export function renderElement (
 ): VNode | void {
   // make sure to expose real self instead of proxy
   const context: Component = this._self
-  const parent: Component | null = renderState.activeInstance
+  const parent: ?Component = renderState.activeInstance
   if (!parent) {
     process.env.NODE_ENV !== 'production' && warn(
       'createElement cannot be called outside of component ' +

+ 2 - 0
src/platforms/web/runtime/components/transition-control.js

@@ -3,6 +3,8 @@
 import { warn } from 'core/util/index'
 
 export default {
+  name: 'transition-control',
+  _abstract: true,
   props: {
     mode: {
       validator (val) {