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)
|
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({
|
||||||
|
|
|
@ -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,23 +251,10 @@ export class VueElement extends BaseClass {
|
||||||
}
|
}
|
||||||
this._numberProps = numberProps
|
this._numberProps = numberProps
|
||||||
|
|
||||||
// check if there are props set pre-upgrade or connect
|
if (isAsync) {
|
||||||
for (const key of Object.keys(this)) {
|
// defining getter/setters on prototype
|
||||||
if (key[0] !== '_' && declaredPropKeys.includes(key)) {
|
// for sync defs, this already happened in the constructor
|
||||||
this._setProp(key, this[key as keyof this], true, false)
|
this._resolveProps(def)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// apply CSS
|
// apply CSS
|
||||||
|
@ -276,12 +266,36 @@ export class VueElement extends BaseClass {
|
||||||
|
|
||||||
const asyncDef = (this._def as ComponentOptions).__asyncLoader
|
const asyncDef = (this._def as ComponentOptions).__asyncLoader
|
||||||
if (asyncDef) {
|
if (asyncDef) {
|
||||||
asyncDef().then(resolve)
|
asyncDef().then(def => resolve(def, true))
|
||||||
} else {
|
} else {
|
||||||
resolve(this._def)
|
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) {
|
protected _setAttr(key: string) {
|
||||||
let value = this.getAttribute(key)
|
let value = this.getAttribute(key)
|
||||||
const camelKey = camelize(key)
|
const camelKey = camelize(key)
|
||||||
|
|
Loading…
Reference in New Issue