feat: attribute fallthrough
This commit is contained in:
parent
6ce39b4d20
commit
cb01733842
@ -1,4 +1,4 @@
|
|||||||
import { EMPTY_OBJ, isReservedProp } from './utils'
|
import { EMPTY_OBJ } from './utils'
|
||||||
import { Component, ComponentClass, MountedComponent } from './component'
|
import { Component, ComponentClass, MountedComponent } from './component'
|
||||||
import { immutable, unwrap, lock, unlock } from '@vue/observer'
|
import { immutable, unwrap, lock, unlock } from '@vue/observer'
|
||||||
import {
|
import {
|
||||||
@ -38,29 +38,42 @@ export function updateProps(instance: MountedComponent, nextProps: Data) {
|
|||||||
// on every component vnode is guarunteed to be a fresh object.
|
// on every component vnode is guarunteed to be a fresh object.
|
||||||
export function normalizeComponentProps(
|
export function normalizeComponentProps(
|
||||||
raw: any,
|
raw: any,
|
||||||
options: ComponentPropsOptions,
|
rawOptions: ComponentPropsOptions,
|
||||||
Component: ComponentClass
|
Component: ComponentClass
|
||||||
): Data {
|
): Data {
|
||||||
if (!raw) {
|
const hasDeclaredProps = rawOptions !== void 0
|
||||||
|
const options = (hasDeclaredProps &&
|
||||||
|
normalizePropsOptions(rawOptions)) as NormalizedPropsOptions
|
||||||
|
if (!raw && !hasDeclaredProps) {
|
||||||
return EMPTY_OBJ
|
return EMPTY_OBJ
|
||||||
}
|
}
|
||||||
const res: Data = {}
|
const res: Data = {}
|
||||||
const normalizedOptions = options && normalizePropsOptions(options)
|
if (raw) {
|
||||||
for (const key in raw) {
|
for (const key in raw) {
|
||||||
if (isReservedProp(key)) {
|
if (key === 'key' || key === 'ref' || key === 'slot') {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (__DEV__ && normalizedOptions != null) {
|
if (hasDeclaredProps) {
|
||||||
validateProp(key, raw[key], normalizedOptions[key], Component)
|
if (options.hasOwnProperty(key)) {
|
||||||
} else {
|
if (__DEV__) {
|
||||||
res[key] = raw[key]
|
validateProp(key, raw[key], options[key], Component)
|
||||||
|
}
|
||||||
|
res[key] = raw[key]
|
||||||
|
} else {
|
||||||
|
// when props are explicitly declared, any non-matching prop is
|
||||||
|
// extracted into attrs instead.
|
||||||
|
;(res.attrs || (res.attrs = {}))[key] = raw[key]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res[key] = raw[key]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// set default values
|
// set default values
|
||||||
if (normalizedOptions != null) {
|
if (hasDeclaredProps) {
|
||||||
for (const key in normalizedOptions) {
|
for (const key in options) {
|
||||||
if (res[key] === void 0) {
|
if (res[key] === void 0) {
|
||||||
const opt = normalizedOptions[key]
|
const opt = options[key]
|
||||||
if (opt != null && opt.hasOwnProperty('default')) {
|
if (opt != null && opt.hasOwnProperty('default')) {
|
||||||
const defaultValue = opt.default
|
const defaultValue = opt.default
|
||||||
res[key] =
|
res[key] =
|
||||||
|
@ -103,30 +103,31 @@ export function normalizeComponentRoot(
|
|||||||
componentVNode &&
|
componentVNode &&
|
||||||
(flags & VNodeFlags.COMPONENT || flags & VNodeFlags.ELEMENT)
|
(flags & VNodeFlags.COMPONENT || flags & VNodeFlags.ELEMENT)
|
||||||
) {
|
) {
|
||||||
const parentData = componentVNode.data || EMPTY_OBJ
|
const parentData = componentVNode.data
|
||||||
const childData = vnode.data || EMPTY_OBJ
|
if (parentData != null) {
|
||||||
let extraData: any = null
|
let extraData: any = null
|
||||||
for (const key in parentData) {
|
for (const key in parentData) {
|
||||||
// class/style bindings on parentVNode are merged down to child
|
// attrs/class/style bindings on parentVNode are merged down to child
|
||||||
// component root.
|
// component root,
|
||||||
if (key === 'class') {
|
// nativeOn* handlers are merged to child root as normal on* handlers.
|
||||||
;(extraData || (extraData = {})).class = childData.class
|
// cloneVNode contains special logic for merging these props with
|
||||||
? [].concat(childData.class, parentData.class)
|
// existing values.
|
||||||
: parentData.class
|
if (key === 'attrs') {
|
||||||
} else if (key === 'style') {
|
extraData = extraData || {}
|
||||||
;(extraData || (extraData = {})).style = childData.style
|
const { attrs } = parentData
|
||||||
? [].concat(childData.style, parentData.style)
|
for (const attr in attrs) {
|
||||||
: parentData.style
|
extraData[attr] = attrs[attr]
|
||||||
} else if (key.startsWith('nativeOn')) {
|
}
|
||||||
// nativeOn* handlers are merged down to child root as native listeners
|
} else if (key === 'class' || key === 'style') {
|
||||||
const event = 'on' + key.slice(8)
|
;(extraData || (extraData = {}))[key] = parentData[key]
|
||||||
;(extraData || (extraData = {}))[event] = childData.event
|
} else if (key.startsWith('nativeOn')) {
|
||||||
? [].concat(childData.event, parentData[key])
|
;(extraData || (extraData = {}))['on' + key.slice(8)] =
|
||||||
: parentData[key]
|
parentData[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (extraData) {
|
||||||
|
vnode = cloneVNode(vnode, extraData)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (extraData) {
|
|
||||||
vnode = cloneVNode(vnode, extraData)
|
|
||||||
}
|
}
|
||||||
if (vnode.el) {
|
if (vnode.el) {
|
||||||
vnode = cloneVNode(vnode)
|
vnode = cloneVNode(vnode)
|
||||||
|
@ -258,7 +258,28 @@ export function cloneVNode(vnode: VNode, extraData?: VNodeData): VNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const key in extraData) {
|
for (const key in extraData) {
|
||||||
clonedData[key] = extraData[key]
|
const existing = clonedData[key]
|
||||||
|
const extra = extraData[key]
|
||||||
|
if (extra === void 0) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// special merge behavior for attrs / class / style / on.
|
||||||
|
let isOn
|
||||||
|
if (key === 'attrs') {
|
||||||
|
clonedData.attrs = existing
|
||||||
|
? Object.assign({}, existing, extra)
|
||||||
|
: extra
|
||||||
|
} else if (
|
||||||
|
key === 'class' ||
|
||||||
|
key === 'style' ||
|
||||||
|
(isOn = key.startsWith('on'))
|
||||||
|
) {
|
||||||
|
// all three props can handle array format, so we simply merge them
|
||||||
|
// by concating.
|
||||||
|
clonedData[key] = existing ? [].concat(existing, extra) : extra
|
||||||
|
} else {
|
||||||
|
clonedData[key] = extra
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return createVNode(
|
return createVNode(
|
||||||
|
Loading…
Reference in New Issue
Block a user