fix(custom-elements): define declared properties in constructor (#5328)

This commit is contained in:
Thorsten Lünborg 2022-11-11 08:46:01 +01:00 committed by GitHub
parent 89f37ceb62
commit 55382aed58
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 58 additions and 20 deletions

View File

@ -215,6 +215,30 @@ describe('defineCustomElement', () => {
expect(el.hasAttribute('not-prop')).toBe(false) expect(el.hasAttribute('not-prop')).toBe(false)
}) })
test('handle properties set before connecting', () => {
const obj = { a: 1 }
const E = defineCustomElement({
props: {
foo: String,
post: Object
},
setup(props) {
expect(props.foo).toBe('hello')
expect(props.post).toBe(obj)
},
render() {
return JSON.stringify(this.post)
}
})
customElements.define('my-el-preconnect', E)
const el = document.createElement('my-el-preconnect') as any
el.foo = 'hello'
el.post = obj
container.appendChild(el)
expect(el.shadowRoot.innerHTML).toBe(JSON.stringify(obj))
})
// https://github.com/vuejs/core/issues/6163 // https://github.com/vuejs/core/issues/6163
test('handle components with no props', async () => { test('handle components with no props', async () => {
const E = defineCustomElement({ const E = defineCustomElement({

View File

@ -186,6 +186,10 @@ export class VueElement extends BaseClass {
) )
} }
this.attachShadow({ mode: 'open' }) this.attachShadow({ mode: 'open' })
if (!(this._def as ComponentOptions).__asyncLoader) {
// for sync component defs we can immediately resolve props
this._resolveProps(this._def)
}
} }
} }
@ -227,9 +231,8 @@ export class VueElement extends BaseClass {
} }
}).observe(this, { attributes: true }) }).observe(this, { attributes: true })
const resolve = (def: InnerComponentDef) => { const resolve = (def: InnerComponentDef, isAsync = false) => {
const { props, styles } = def const { props, styles } = def
const declaredPropKeys = isArray(props) ? props : Object.keys(props || {})
// cast Number-type props set before resolve // cast Number-type props set before resolve
let numberProps let numberProps
@ -248,6 +251,31 @@ export class VueElement extends BaseClass {
} }
this._numberProps = numberProps this._numberProps = numberProps
if (isAsync) {
// defining getter/setters on prototype
// for sync defs, this already happened in the constructor
this._resolveProps(def)
}
// apply CSS
this._applyStyles(styles)
// initial render
this._update()
}
const asyncDef = (this._def as ComponentOptions).__asyncLoader
if (asyncDef) {
asyncDef().then(def => resolve(def, true))
} else {
resolve(this._def)
}
}
private _resolveProps(def: InnerComponentDef) {
const { props } = def
const declaredPropKeys = isArray(props) ? props : Object.keys(props || {})
// 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)) {
@ -266,20 +294,6 @@ export class VueElement extends BaseClass {
} }
}) })
} }
// apply CSS
this._applyStyles(styles)
// initial render
this._update()
}
const asyncDef = (this._def as ComponentOptions).__asyncLoader
if (asyncDef) {
asyncDef().then(resolve)
} else {
resolve(this._def)
}
} }
protected _setAttr(key: string) { protected _setAttr(key: string) {