fix(custom-element): fix custom element props access on initial render
ref: #4792
This commit is contained in:
		
							parent
							
								
									6916d725a0
								
							
						
					
					
						commit
						4b7f76e36a
					
				@ -191,13 +191,21 @@ describe('defineCustomElement', () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    test('handling properties set before upgrading', () => {
 | 
					    test('handling properties set before upgrading', () => {
 | 
				
			||||||
      const E = defineCustomElement({
 | 
					      const E = defineCustomElement({
 | 
				
			||||||
        props: ['foo'],
 | 
					        props: {
 | 
				
			||||||
 | 
					          foo: String,
 | 
				
			||||||
 | 
					          dataAge: Number
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        setup(props) {
 | 
				
			||||||
 | 
					          expect(props.foo).toBe('hello')
 | 
				
			||||||
 | 
					          expect(props.dataAge).toBe(5)
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
        render() {
 | 
					        render() {
 | 
				
			||||||
          return `foo: ${this.foo}`
 | 
					          return `foo: ${this.foo}`
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
      const el = document.createElement('my-el-upgrade') as any
 | 
					      const el = document.createElement('my-el-upgrade') as any
 | 
				
			||||||
      el.foo = 'hello'
 | 
					      el.foo = 'hello'
 | 
				
			||||||
 | 
					      el.dataset.age = 5
 | 
				
			||||||
      container.appendChild(el)
 | 
					      container.appendChild(el)
 | 
				
			||||||
      customElements.define('my-el-upgrade', E)
 | 
					      customElements.define('my-el-upgrade', E)
 | 
				
			||||||
      expect(el.shadowRoot.innerHTML).toBe(`foo: hello`)
 | 
					      expect(el.shadowRoot.innerHTML).toBe(`foo: hello`)
 | 
				
			||||||
@ -363,10 +371,10 @@ describe('defineCustomElement', () => {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      // should inject styles
 | 
					      // should inject styles
 | 
				
			||||||
      expect(e1.shadowRoot!.innerHTML).toBe(
 | 
					      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(
 | 
					      expect(e2.shadowRoot!.innerHTML).toBe(
 | 
				
			||||||
        `<div>world</div><style>div { color: red }</style>`
 | 
					        `<style>div { color: red }</style><div>world</div>`
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // attr
 | 
					      // attr
 | 
				
			||||||
@ -374,7 +382,7 @@ describe('defineCustomElement', () => {
 | 
				
			|||||||
      await nextTick()
 | 
					      await nextTick()
 | 
				
			||||||
      expect((e1 as any).msg).toBe('attr')
 | 
					      expect((e1 as any).msg).toBe('attr')
 | 
				
			||||||
      expect(e1.shadowRoot!.innerHTML).toBe(
 | 
					      expect(e1.shadowRoot!.innerHTML).toBe(
 | 
				
			||||||
        `<div>attr</div><style>div { color: red }</style>`
 | 
					        `<style>div { color: red }</style><div>attr</div>`
 | 
				
			||||||
      )
 | 
					      )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // props
 | 
					      // props
 | 
				
			||||||
@ -382,7 +390,7 @@ describe('defineCustomElement', () => {
 | 
				
			|||||||
      ;(e1 as any).msg = 'prop'
 | 
					      ;(e1 as any).msg = 'prop'
 | 
				
			||||||
      expect(e1.getAttribute('msg')).toBe('prop')
 | 
					      expect(e1.getAttribute('msg')).toBe('prop')
 | 
				
			||||||
      expect(e1.shadowRoot!.innerHTML).toBe(
 | 
					      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(() => {
 | 
					        defineAsyncComponent(() => {
 | 
				
			||||||
          return Promise.resolve({
 | 
					          return Promise.resolve({
 | 
				
			||||||
            props: ['msg'],
 | 
					            props: ['msg'],
 | 
				
			||||||
 | 
					            setup(props) {
 | 
				
			||||||
 | 
					              expect(typeof props.msg).toBe('string')
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
            render(this: any) {
 | 
					            render(this: any) {
 | 
				
			||||||
              return h('div', this.msg)
 | 
					              return h('div', this.msg)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -429,6 +440,9 @@ describe('defineCustomElement', () => {
 | 
				
			|||||||
        defineAsyncComponent(() => {
 | 
					        defineAsyncComponent(() => {
 | 
				
			||||||
          return Promise.resolve({
 | 
					          return Promise.resolve({
 | 
				
			||||||
            props: { n: Number },
 | 
					            props: { n: Number },
 | 
				
			||||||
 | 
					            setup(props) {
 | 
				
			||||||
 | 
					              expect(props.n).toBe(20)
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
            render(this: any) {
 | 
					            render(this: any) {
 | 
				
			||||||
              return h('div', this.n + ',' + typeof this.n)
 | 
					              return h('div', this.n + ',' + typeof this.n)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
				
			|||||||
@ -180,7 +180,6 @@ export class VueElement extends BaseClass {
 | 
				
			|||||||
    this._connected = true
 | 
					    this._connected = true
 | 
				
			||||||
    if (!this._instance) {
 | 
					    if (!this._instance) {
 | 
				
			||||||
      this._resolveDef()
 | 
					      this._resolveDef()
 | 
				
			||||||
      this._update()
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -231,17 +230,15 @@ export class VueElement extends BaseClass {
 | 
				
			|||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (numberProps) {
 | 
					      this._numberProps = numberProps
 | 
				
			||||||
        this._numberProps = numberProps
 | 
					 | 
				
			||||||
        this._update()
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // 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] !== '_') {
 | 
					        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
 | 
					      // defining getter/setters on prototype
 | 
				
			||||||
      for (const key of rawKeys.map(camelize)) {
 | 
					      for (const key of rawKeys.map(camelize)) {
 | 
				
			||||||
        Object.defineProperty(this, key, {
 | 
					        Object.defineProperty(this, key, {
 | 
				
			||||||
@ -253,7 +250,12 @@ export class VueElement extends BaseClass {
 | 
				
			|||||||
          }
 | 
					          }
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // apply CSS
 | 
				
			||||||
      this._applyStyles(styles)
 | 
					      this._applyStyles(styles)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // initial render
 | 
				
			||||||
 | 
					      this._update()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const asyncDef = (this._def as ComponentOptions).__asyncLoader
 | 
					    const asyncDef = (this._def as ComponentOptions).__asyncLoader
 | 
				
			||||||
@ -282,10 +284,15 @@ export class VueElement extends BaseClass {
 | 
				
			|||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * @internal
 | 
					   * @internal
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
  protected _setProp(key: string, val: any, shouldReflect = true) {
 | 
					  protected _setProp(
 | 
				
			||||||
 | 
					    key: string,
 | 
				
			||||||
 | 
					    val: any,
 | 
				
			||||||
 | 
					    shouldReflect = true,
 | 
				
			||||||
 | 
					    shouldUpdate = true
 | 
				
			||||||
 | 
					  ) {
 | 
				
			||||||
    if (val !== this._props[key]) {
 | 
					    if (val !== this._props[key]) {
 | 
				
			||||||
      this._props[key] = val
 | 
					      this._props[key] = val
 | 
				
			||||||
      if (this._instance) {
 | 
					      if (shouldUpdate && this._instance) {
 | 
				
			||||||
        this._update()
 | 
					        this._update()
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      // reflect
 | 
					      // reflect
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user