Просмотр исходного кода

fix(custom-element): use PatchFlags.BAIL for slot when props are present (#13907)

close #13904
edison 7 месяцев назад
Родитель
Сommit
5358bca4a8

+ 2 - 1
packages/runtime-core/src/helpers/renderSlot.ts

@@ -37,6 +37,7 @@ export function renderSlot(
       isAsyncWrapper(currentRenderingInstance!.parent) &&
       currentRenderingInstance!.parent.ce)
   ) {
+    const hasProps = Object.keys(props).length > 0
     // in custom element mode, render <slot/> as actual slot outlets
     // wrap it with a fragment because in shadowRoot: false mode the slot
     // element gets replaced by injected content
@@ -47,7 +48,7 @@ export function renderSlot(
         Fragment,
         null,
         [createVNode('slot', props, fallback && fallback())],
-        PatchFlags.STABLE_FRAGMENT,
+        hasProps ? PatchFlags.BAIL : PatchFlags.STABLE_FRAGMENT,
       )
     )
   }

+ 27 - 0
packages/runtime-dom/__tests__/customElement.spec.ts

@@ -638,6 +638,33 @@ describe('defineCustomElement', () => {
         `<div><slot><div>fallback</div></slot></div><div><slot name="named"></slot></div>`,
       )
     })
+
+    test('render slot props', async () => {
+      const foo = ref('foo')
+      const E = defineCustomElement({
+        render() {
+          return [
+            h(
+              'div',
+              null,
+              renderSlot(this.$slots, 'default', { class: foo.value }),
+            ),
+          ]
+        },
+      })
+      customElements.define('my-el-slot-props', E)
+      container.innerHTML = `<my-el-slot-props><span>hi</span></my-el-slot-props>`
+      const e = container.childNodes[0] as VueElement
+      expect(e.shadowRoot!.innerHTML).toBe(
+        `<div><slot class="foo"></slot></div>`,
+      )
+
+      foo.value = 'bar'
+      await nextTick()
+      expect(e.shadowRoot!.innerHTML).toBe(
+        `<div><slot class="bar"></slot></div>`,
+      )
+    })
   })
 
   describe('provide/inject', () => {