Skip to content

Commit

Permalink
fix(custom-element): fix custom element props access on initial render
Browse files Browse the repository at this point in the history
ref: #4792
  • Loading branch information
yyx990803 committed Nov 2, 2021
1 parent 6916d72 commit 4b7f76e
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 13 deletions.
24 changes: 19 additions & 5 deletions packages/runtime-dom/__tests__/customElement.spec.ts
Expand Up @@ -191,13 +191,21 @@ describe('defineCustomElement', () => {

test('handling properties set before upgrading', () => {
const E = defineCustomElement({
props: ['foo'],
props: {
foo: String,
dataAge: Number
},
setup(props) {
expect(props.foo).toBe('hello')
expect(props.dataAge).toBe(5)
},
render() {
return `foo: ${this.foo}`
}
})
const el = document.createElement('my-el-upgrade') as any
el.foo = 'hello'
el.dataset.age = 5
container.appendChild(el)
customElements.define('my-el-upgrade', E)
expect(el.shadowRoot.innerHTML).toBe(`foo: hello`)
Expand Down Expand Up @@ -363,26 +371,26 @@ describe('defineCustomElement', () => {

// should inject styles
expect(e1.shadowRoot!.innerHTML).toBe(
`<div>hello</div><style>div { color: red }</style>`
`<style>div { color: red }</style><div>hello</div>`
)
expect(e2.shadowRoot!.innerHTML).toBe(
`<div>world</div><style>div { color: red }</style>`
`<style>div { color: red }</style><div>world</div>`
)

// attr
e1.setAttribute('msg', 'attr')
await nextTick()
expect((e1 as any).msg).toBe('attr')
expect(e1.shadowRoot!.innerHTML).toBe(
`<div>attr</div><style>div { color: red }</style>`
`<style>div { color: red }</style><div>attr</div>`
)

// props
expect(`msg` in e1).toBe(true)
;(e1 as any).msg = 'prop'
expect(e1.getAttribute('msg')).toBe('prop')
expect(e1.shadowRoot!.innerHTML).toBe(
`<div>prop</div><style>div { color: red }</style>`
`<style>div { color: red }</style><div>prop</div>`
)
})

Expand All @@ -391,6 +399,9 @@ describe('defineCustomElement', () => {
defineAsyncComponent(() => {
return Promise.resolve({
props: ['msg'],
setup(props) {
expect(typeof props.msg).toBe('string')
},
render(this: any) {
return h('div', this.msg)
}
Expand Down Expand Up @@ -429,6 +440,9 @@ describe('defineCustomElement', () => {
defineAsyncComponent(() => {
return Promise.resolve({
props: { n: Number },
setup(props) {
expect(props.n).toBe(20)
},
render(this: any) {
return h('div', this.n + ',' + typeof this.n)
}
Expand Down
23 changes: 15 additions & 8 deletions packages/runtime-dom/src/apiCustomElement.ts
Expand Up @@ -180,7 +180,6 @@ export class VueElement extends BaseClass {
this._connected = true
if (!this._instance) {
this._resolveDef()
this._update()
}
}

Expand Down Expand Up @@ -231,17 +230,15 @@ export class VueElement extends BaseClass {
}
}
}
if (numberProps) {
this._numberProps = numberProps
this._update()
}
this._numberProps = numberProps

// check if there are props set pre-upgrade or connect
for (const key of Object.keys(this)) {
if (key[0] !== '_') {
this._setProp(key, this[key as keyof this])
this._setProp(key, this[key as keyof this], true, false)
}
}

// defining getter/setters on prototype
for (const key of rawKeys.map(camelize)) {
Object.defineProperty(this, key, {
Expand All @@ -253,7 +250,12 @@ export class VueElement extends BaseClass {
}
})
}

// apply CSS
this._applyStyles(styles)

// initial render
this._update()
}

const asyncDef = (this._def as ComponentOptions).__asyncLoader
Expand Down Expand Up @@ -282,10 +284,15 @@ export class VueElement extends BaseClass {
/**
* @internal
*/
protected _setProp(key: string, val: any, shouldReflect = true) {
protected _setProp(
key: string,
val: any,
shouldReflect = true,
shouldUpdate = true
) {
if (val !== this._props[key]) {
this._props[key] = val
if (this._instance) {
if (shouldUpdate && this._instance) {
this._update()
}
// reflect
Expand Down

0 comments on commit 4b7f76e

Please sign in to comment.