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

fix(custom-element): properly locate parent when slotted in shadow dom (#12480)

close #12479
lejunyang 1 месяц назад
Родитель
Сommit
f06c81aa3d

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

@@ -995,6 +995,31 @@ describe('defineCustomElement', () => {
       )
     })
 
+    test('should resolve correct parent when element is slotted in shadow DOM', async () => {
+      const GrandParent = defineCustomElement({
+        provide: {
+          foo: ref('GrandParent'),
+        },
+        render() {
+          return h('my-parent-in-shadow', h('slot'))
+        },
+      })
+      const Parent = defineCustomElement({
+        provide: {
+          foo: ref('Parent'),
+        },
+        render() {
+          return h('slot')
+        },
+      })
+      customElements.define('my-grand-parent', GrandParent)
+      customElements.define('my-parent-in-shadow', Parent)
+      container.innerHTML = `<my-grand-parent><my-consumer></my-consumer></my-grand-parent>`
+      const grandParent = container.childNodes[0] as VueElement,
+        consumer = grandParent.firstElementChild as VueElement
+      expect(consumer.shadowRoot!.textContent).toBe('Parent')
+    })
+
     // #13212
     test('inherited from app context within nested elements', async () => {
       const outerValues: (string | undefined)[] = []

+ 6 - 1
packages/runtime-dom/src/apiCustomElement.ts

@@ -291,7 +291,12 @@ export class VueElement
     // locate nearest Vue custom element parent for provide/inject
     let parent: Node | null = this
     while (
-      (parent = parent && (parent.parentNode || (parent as ShadowRoot).host))
+      (parent =
+        parent &&
+        // #12479 should check assignedSlot first to get correct parent
+        ((parent as Element).assignedSlot ||
+          parent.parentNode ||
+          (parent as ShadowRoot).host))
     ) {
       if (parent instanceof VueElement) {
         this._parent = parent