2024-11-14 20:01:10 +08:00
|
|
|
import { camelize, isArray, normalizeClass, normalizeStyle } from '@vue/shared'
|
2024-03-19 00:24:58 +08:00
|
|
|
import { type ComponentInternalInstance, currentInstance } from './component'
|
2024-03-16 18:54:36 +08:00
|
|
|
import { isEmitListener } from './componentEmits'
|
2024-11-13 16:53:44 +08:00
|
|
|
import { type RawProps, walkRawProps } from './componentProps'
|
2024-03-19 00:24:58 +08:00
|
|
|
import { renderEffect } from './renderEffect'
|
2024-11-14 20:01:10 +08:00
|
|
|
import { mergeProp, setDynamicProp } from './dom/prop'
|
2024-03-16 18:54:36 +08:00
|
|
|
|
2024-11-14 20:01:10 +08:00
|
|
|
export function patchAttrs(
|
|
|
|
instance: ComponentInternalInstance,
|
|
|
|
hasDynamicProps?: boolean,
|
|
|
|
): void {
|
2024-04-15 02:58:32 +08:00
|
|
|
const {
|
|
|
|
attrs,
|
|
|
|
rawProps,
|
|
|
|
propsOptions: [options],
|
|
|
|
} = instance
|
2024-03-16 18:54:36 +08:00
|
|
|
|
2024-04-30 23:09:59 +08:00
|
|
|
if (!rawProps.length) return
|
2024-03-16 18:54:36 +08:00
|
|
|
const keys = new Set<string>()
|
2024-11-14 20:01:10 +08:00
|
|
|
const classes: any[] = []
|
|
|
|
const styles: any[] = []
|
2024-03-16 18:54:36 +08:00
|
|
|
|
2024-11-13 16:53:44 +08:00
|
|
|
walkRawProps(rawProps, registerAttr)
|
2024-03-16 18:54:36 +08:00
|
|
|
for (const key in attrs) {
|
|
|
|
if (!keys.has(key)) {
|
|
|
|
delete attrs[key]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-14 20:01:10 +08:00
|
|
|
setClassOrStyle(classes, 'class', normalizeClass)
|
|
|
|
setClassOrStyle(styles, 'style', normalizeStyle)
|
|
|
|
|
|
|
|
function setClassOrStyle(
|
|
|
|
values: any[],
|
|
|
|
field: 'class' | 'style',
|
|
|
|
normalize: (value: any) => any,
|
|
|
|
) {
|
|
|
|
if (values.length) {
|
|
|
|
if (hasDynamicProps) {
|
|
|
|
Object.defineProperty(attrs, field, {
|
|
|
|
get() {
|
|
|
|
return normalize(values.map(value => value()))
|
|
|
|
},
|
|
|
|
enumerable: true,
|
|
|
|
configurable: true,
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
attrs[field] = normalizeClass(values)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-30 23:09:59 +08:00
|
|
|
function registerAttr(key: string, value: any, getter?: boolean) {
|
2024-03-16 18:54:36 +08:00
|
|
|
if (
|
|
|
|
(!options || !(camelize(key) in options)) &&
|
2024-04-30 23:09:59 +08:00
|
|
|
!isEmitListener(instance.emitsOptions, key) &&
|
2024-11-14 20:01:10 +08:00
|
|
|
(key === 'class' || key === 'style' || !keys.has(key))
|
2024-03-16 18:54:36 +08:00
|
|
|
) {
|
|
|
|
keys.add(key)
|
2024-11-14 20:01:10 +08:00
|
|
|
|
|
|
|
if (key === 'class' || key === 'style') {
|
|
|
|
;(key === 'class' ? classes : styles).push(
|
|
|
|
hasDynamicProps ? (getter ? value : () => value) : value,
|
|
|
|
)
|
|
|
|
} else if (getter) {
|
2024-04-30 23:09:59 +08:00
|
|
|
Object.defineProperty(attrs, key, {
|
|
|
|
get: value,
|
|
|
|
enumerable: true,
|
|
|
|
configurable: true,
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
attrs[key] = value
|
|
|
|
}
|
2024-03-16 18:54:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-03-19 00:24:58 +08:00
|
|
|
|
|
|
|
export function withAttrs(props: RawProps): RawProps {
|
|
|
|
const instance = currentInstance!
|
2024-06-21 14:03:11 +08:00
|
|
|
if (instance.type.inheritAttrs === false) return props
|
2024-03-19 00:24:58 +08:00
|
|
|
const attrsGetter = () => instance.attrs
|
|
|
|
if (!props) return [attrsGetter]
|
|
|
|
if (isArray(props)) {
|
|
|
|
return [attrsGetter, ...props]
|
|
|
|
}
|
|
|
|
return [attrsGetter, props]
|
|
|
|
}
|
|
|
|
|
2024-08-09 16:56:59 +08:00
|
|
|
export function fallThroughAttrs(instance: ComponentInternalInstance): void {
|
2024-03-19 00:24:58 +08:00
|
|
|
const {
|
|
|
|
block,
|
2024-06-21 14:03:11 +08:00
|
|
|
type: { inheritAttrs },
|
2024-11-14 20:01:10 +08:00
|
|
|
dynamicAttrs,
|
2024-03-19 00:24:58 +08:00
|
|
|
} = instance
|
2024-11-14 20:01:10 +08:00
|
|
|
if (
|
|
|
|
inheritAttrs === false ||
|
|
|
|
!(block instanceof Element) ||
|
|
|
|
// all props as dynamic
|
|
|
|
dynamicAttrs === true
|
|
|
|
)
|
|
|
|
return
|
2024-03-19 00:24:58 +08:00
|
|
|
|
2024-11-14 20:01:10 +08:00
|
|
|
const hasStaticAttrs = dynamicAttrs || dynamicAttrs === false
|
|
|
|
|
|
|
|
let initial: Record<string, string> | undefined
|
|
|
|
if (hasStaticAttrs) {
|
2024-11-13 15:45:28 +08:00
|
|
|
// attrs in static template
|
2024-11-14 20:01:10 +08:00
|
|
|
initial = {}
|
2024-11-13 15:45:28 +08:00
|
|
|
for (let i = 0; i < block.attributes.length; i++) {
|
|
|
|
const attr = block.attributes[i]
|
2024-11-14 20:01:10 +08:00
|
|
|
if (dynamicAttrs && dynamicAttrs.includes(attr.name)) continue
|
2024-11-13 15:45:28 +08:00
|
|
|
initial[attr.name] = attr.value
|
|
|
|
}
|
2024-03-19 00:24:58 +08:00
|
|
|
}
|
2024-11-14 20:01:10 +08:00
|
|
|
|
|
|
|
renderEffect(() => {
|
|
|
|
for (const key in instance.attrs) {
|
|
|
|
if (dynamicAttrs && dynamicAttrs.includes(key)) continue
|
|
|
|
|
|
|
|
let value: unknown
|
|
|
|
if (hasStaticAttrs) {
|
|
|
|
value = mergeProp(key, instance.attrs[key], initial![key])
|
|
|
|
} else {
|
|
|
|
value = instance.attrs[key]
|
|
|
|
}
|
|
|
|
|
|
|
|
setDynamicProp(block, key, value)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
export function setInheritAttrs(dynamicAttrs?: string[] | boolean): void {
|
|
|
|
const instance = currentInstance!
|
|
|
|
if (instance.type.inheritAttrs === false) return
|
|
|
|
instance.dynamicAttrs = dynamicAttrs
|
2024-03-19 00:24:58 +08:00
|
|
|
}
|