fix(custom-element): reflect prop default value on custom element

close #9006
close #10537
This commit is contained in:
Evan You 2024-08-07 02:51:29 +08:00
parent bcb9a70290
commit 63689ed776
No known key found for this signature in database
GPG Key ID: 00E9AB7A6704CE0A
4 changed files with 37 additions and 10 deletions

View File

@ -1247,4 +1247,13 @@ export interface ComponentCustomElementInterface {
* @internal * @internal
*/ */
_removeChildStyle(type: ConcreteComponent): void _removeChildStyle(type: ConcreteComponent): void
/**
* @internal
*/
_setProp(
key: string,
val: any,
shouldReflect?: boolean,
shouldUpdate?: boolean,
): void
} }

View File

@ -480,6 +480,10 @@ function resolvePropValue(
} else { } else {
value = defaultValue value = defaultValue
} }
// #9006 reflect default value on custom element
if (instance.ce) {
instance.ce._setProp(key, value)
}
} }
// boolean casting // boolean casting
if (opt[BooleanFlags.shouldCast]) { if (opt[BooleanFlags.shouldCast]) {

View File

@ -338,7 +338,7 @@ describe('defineCustomElement', () => {
expect(el.shadowRoot!.innerHTML).toMatchInlineSnapshot('"<div>foo</div>"') expect(el.shadowRoot!.innerHTML).toMatchInlineSnapshot('"<div>foo</div>"')
}) })
// # 5793 // #5793
test('set number value in dom property', () => { test('set number value in dom property', () => {
const E = defineCustomElement({ const E = defineCustomElement({
props: { props: {
@ -357,6 +357,25 @@ describe('defineCustomElement', () => {
expect(el.shadowRoot.innerHTML).toBe('max age: 50/type: number') expect(el.shadowRoot.innerHTML).toBe('max age: 50/type: number')
}) })
// #9006
test('should reflect default value', () => {
const E = defineCustomElement({
props: {
value: {
type: String,
default: 'hi',
},
},
render() {
return this.value
},
})
customElements.define('my-el-default-val', E)
container.innerHTML = `<my-el-default-val></my-el-default-val>`
const e = container.childNodes[0] as any
expect(e.value).toBe('hi')
})
test('support direct setup function syntax with extra options', () => { test('support direct setup function syntax with extra options', () => {
const E = defineCustomElement( const E = defineCustomElement(
props => { props => {

View File

@ -395,7 +395,7 @@ export class VueElement
// check if there are props set pre-upgrade or connect // check if there are props set pre-upgrade or connect
for (const key of Object.keys(this)) { for (const key of Object.keys(this)) {
if (key[0] !== '_' && declaredPropKeys.includes(key)) { if (key[0] !== '_' && declaredPropKeys.includes(key)) {
this._setProp(key, this[key as keyof this], true, false) this._setProp(key, this[key as keyof this])
} }
} }
@ -406,7 +406,7 @@ export class VueElement
return this._getProp(key) return this._getProp(key)
}, },
set(val) { set(val) {
this._setProp(key, val) this._setProp(key, val, true, true)
}, },
}) })
} }
@ -435,7 +435,7 @@ export class VueElement
if (this._numberProps && this._numberProps[camelKey]) { if (this._numberProps && this._numberProps[camelKey]) {
value = toNumber(value) value = toNumber(value)
} }
this._setProp(camelKey, value, false) this._setProp(camelKey, value, false, true)
} }
/** /**
@ -448,12 +448,7 @@ export class VueElement
/** /**
* @internal * @internal
*/ */
protected _setProp( _setProp(key: string, val: any, shouldReflect = true, shouldUpdate = false) {
key: string,
val: any,
shouldReflect = true,
shouldUpdate = true,
) {
if (val !== this._props[key]) { if (val !== this._props[key]) {
this._props[key] = val this._props[key] = val
if (shouldUpdate && this._instance) { if (shouldUpdate && this._instance) {