mirror of https://github.com/vuejs/core.git
fix(custom-elements): define declared properties in constructor (#5328)
This commit is contained in:
parent
89f37ceb62
commit
55382aed58
|
@ -215,6 +215,30 @@ describe('defineCustomElement', () => {
|
|||
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
|
||||
test('handle components with no props', async () => {
|
||||
const E = defineCustomElement({
|
||||
|
|
|
@ -186,6 +186,10 @@ export class VueElement extends BaseClass {
|
|||
)
|
||||
}
|
||||
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 })
|
||||
|
||||
const resolve = (def: InnerComponentDef) => {
|
||||
const resolve = (def: InnerComponentDef, isAsync = false) => {
|
||||
const { props, styles } = def
|
||||
const declaredPropKeys = isArray(props) ? props : Object.keys(props || {})
|
||||
|
||||
// cast Number-type props set before resolve
|
||||
let numberProps
|
||||
|
@ -248,23 +251,10 @@ export class VueElement extends BaseClass {
|
|||
}
|
||||
this._numberProps = numberProps
|
||||
|
||||
// check if there are props set pre-upgrade or connect
|
||||
for (const key of Object.keys(this)) {
|
||||
if (key[0] !== '_' && declaredPropKeys.includes(key)) {
|
||||
this._setProp(key, this[key as keyof this], true, false)
|
||||
}
|
||||
}
|
||||
|
||||
// defining getter/setters on prototype
|
||||
for (const key of declaredPropKeys.map(camelize)) {
|
||||
Object.defineProperty(this, key, {
|
||||
get() {
|
||||
return this._getProp(key)
|
||||
},
|
||||
set(val) {
|
||||
this._setProp(key, val)
|
||||
}
|
||||
})
|
||||
if (isAsync) {
|
||||
// defining getter/setters on prototype
|
||||
// for sync defs, this already happened in the constructor
|
||||
this._resolveProps(def)
|
||||
}
|
||||
|
||||
// apply CSS
|
||||
|
@ -276,12 +266,36 @@ export class VueElement extends BaseClass {
|
|||
|
||||
const asyncDef = (this._def as ComponentOptions).__asyncLoader
|
||||
if (asyncDef) {
|
||||
asyncDef().then(resolve)
|
||||
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
|
||||
for (const key of Object.keys(this)) {
|
||||
if (key[0] !== '_' && declaredPropKeys.includes(key)) {
|
||||
this._setProp(key, this[key as keyof this], true, false)
|
||||
}
|
||||
}
|
||||
|
||||
// defining getter/setters on prototype
|
||||
for (const key of declaredPropKeys.map(camelize)) {
|
||||
Object.defineProperty(this, key, {
|
||||
get() {
|
||||
return this._getProp(key)
|
||||
},
|
||||
set(val) {
|
||||
this._setProp(key, val)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
protected _setAttr(key: string) {
|
||||
let value = this.getAttribute(key)
|
||||
const camelKey = camelize(key)
|
||||
|
|
Loading…
Reference in New Issue