]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(custom-element): fix custom element props access on initial render
authorEvan You <yyx990803@gmail.com>
Tue, 2 Nov 2021 05:20:31 +0000 (13:20 +0800)
committerEvan You <yyx990803@gmail.com>
Tue, 2 Nov 2021 05:20:31 +0000 (13:20 +0800)
ref: #4792

packages/runtime-dom/__tests__/customElement.spec.ts
packages/runtime-dom/src/apiCustomElement.ts

index 60b51de38937f4a79fc50027c6685eb26aa90404..777f9677d048d61e0520e59aed577d6817f10f1a 100644 (file)
@@ -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`)
@@ -363,10 +371,10 @@ 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
@@ -374,7 +382,7 @@ describe('defineCustomElement', () => {
       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
@@ -382,7 +390,7 @@ describe('defineCustomElement', () => {
       ;(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>`
       )
     })
 
@@ -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)
             }
@@ -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)
             }
index a532da4c6c7f51cd945ee37ff4ab397cf474a70e..5127e4a47f543b4e3b6005c0ee3b6cef6670f62f 100644 (file)
@@ -180,7 +180,6 @@ export class VueElement extends BaseClass {
     this._connected = true
     if (!this._instance) {
       this._resolveDef()
-      this._update()
     }
   }
 
@@ -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, {
@@ -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
@@ -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