wip: class/style fallthrough compat

This commit is contained in:
Evan You 2021-04-21 22:04:26 -04:00
parent a75b00c558
commit 12abd4af85
5 changed files with 66 additions and 32 deletions

View File

@ -0,0 +1,22 @@
import { isOn } from '@vue/shared'
import { ComponentInternalInstance } from '../component'
import { DeprecationTypes, isCompatEnabled } from './compatConfig'
export function shouldSkipAttr(
key: string,
instance: ComponentInternalInstance
): boolean {
if (
(key === 'class' || key === 'style') &&
isCompatEnabled(DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE, instance)
) {
return true
}
if (
isOn(key) &&
isCompatEnabled(DeprecationTypes.INSTANCE_LISTENERS, instance)
) {
return true
}
return false
}

View File

@ -216,15 +216,15 @@ const deprecationData: Record<DeprecationTypes, DeprecationData> = {
},
[DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE]: {
message:
`vm.$attrs now includes class and style bindings passed from parent. ` +
`Components with inheritAttrs: false will no longer auto-inherit ` +
`class/style on its root element. If your code relies on this behavior, ` +
`you may see broken styling and need to adjust your CSS. Otherwise, ` +
`you can disable the compat behavior and suppress this warning with:` +
`\n\n configureCompat({ ${
DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE
}: false )\n`,
message: componentName =>
`Component <${componentName}> has \`inheritAttrs: false\` but is ` +
`relying on class/style fallthrough from parent. In Vue 3, class/style ` +
`are now included in $attrs and will no longer fallthrough when ` +
`inheritAttrs is false. If you are already using v-bind="$attrs" on ` +
`component root it should render the same end result. ` +
`If you are binding $attrs to a non-root element and expecting ` +
`class/style to fallthrough on root, you will need to now manually bind ` +
`them on root via :class="$attrs.class".`,
link: `https://v3.vuejs.org/guide/migration/attrs-includes-class-style.html`
},

View File

@ -4,7 +4,6 @@ import { getCompatChildren } from './instanceChildren'
import {
DeprecationTypes,
assertCompatEnabled,
checkCompatEnabled,
isCompatEnabled
} from './compatConfig'
import { off, on, once } from './instanceEventEmitter'
@ -75,14 +74,6 @@ export function installCompatInstanceProperties(map: PublicPropertiesMap) {
return __DEV__ ? shallowReadonly(i.slots) : i.slots
},
// overrides existing accessor
$attrs: i => {
if (__DEV__ && i.type.inheritAttrs === false) {
checkCompatEnabled(DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE, i)
}
return __DEV__ ? shallowReadonly(i.attrs) : i.attrs
},
$on: i => on.bind(null, i),
$once: i => once.bind(null, i),
$off: i => off.bind(null, i),

View File

@ -20,8 +20,7 @@ import {
isReservedProp,
EMPTY_ARR,
def,
extend,
isOn
extend
} from '@vue/shared'
import { warn } from './warning'
import {
@ -37,6 +36,7 @@ import { AppContext } from './apiCreateApp'
import { createPropsDefaultThis } from './compat/props'
import { isCompatEnabled, softAssertCompatEnabled } from './compat/compatConfig'
import { DeprecationTypes } from './compat/compatConfig'
import { shouldSkipAttr } from './compat/attrsFallthrough'
export type ComponentPropsOptions<P = Data> =
| ComponentObjectPropsOptions<P>
@ -229,11 +229,7 @@ export function updateProps(
)
}
} else {
if (
__COMPAT__ &&
isOn(key) &&
isCompatEnabled(DeprecationTypes.INSTANCE_LISTENERS, instance)
) {
if (__COMPAT__ && shouldSkipAttr(key, instance)) {
continue
}
if (value !== attrs[key]) {
@ -341,11 +337,7 @@ function setFullProps(
// Any non-declared (either as a prop or an emitted event) props are put
// into a separate `attrs` object for spreading. Make sure to preserve
// original key casing
if (
__COMPAT__ &&
isOn(key) &&
isCompatEnabled(DeprecationTypes.INSTANCE_LISTENERS, instance)
) {
if (__COMPAT__ && shouldSkipAttr(key, instance)) {
continue
}
if (value !== attrs[key]) {

View File

@ -1,7 +1,8 @@
import {
ComponentInternalInstance,
FunctionalComponent,
Data
Data,
getComponentName
} from './component'
import {
VNode,
@ -20,6 +21,11 @@ import { isHmrUpdating } from './hmr'
import { NormalizedProps } from './componentProps'
import { isEmitListener } from './componentEmits'
import { setCurrentRenderingInstance } from './componentRenderContext'
import {
DeprecationTypes,
isCompatEnabled,
warnDeprecation
} from './compat/compatConfig'
/**
* dev only flag to track whether $attrs was used during render.
@ -117,7 +123,7 @@ export function renderComponentRoot(
;[root, setRoot] = getChildRoot(result)
}
if (Component.inheritAttrs !== false && fallthroughAttrs) {
if (fallthroughAttrs && Component.inheritAttrs !== false) {
const keys = Object.keys(fallthroughAttrs)
const { shapeFlag } = root
if (keys.length) {
@ -175,6 +181,29 @@ export function renderComponentRoot(
}
}
if (
__COMPAT__ &&
isCompatEnabled(DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE, instance) &&
vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT &&
(root.shapeFlag & ShapeFlags.ELEMENT ||
root.shapeFlag & ShapeFlags.COMPONENT)
) {
const { class: cls, style } = vnode.props || {}
if (cls || style) {
if (__DEV__ && Component.inheritAttrs === false) {
warnDeprecation(
DeprecationTypes.INSTANCE_ATTRS_CLASS_STYLE,
instance,
getComponentName(instance.type)
)
}
root = cloneVNode(root, {
class: cls,
style: style
})
}
}
// inherit directives
if (vnode.dirs) {
if (__DEV__ && !isElementRoot(root)) {