karol-f / vue-custom-element

Vue Custom Element - Web Components' Custom Elements for Vue.js
https://karol-f.github.io/vue-custom-element/
MIT License
1.97k stars 187 forks source link

Using vue-custom-element outside vue application: default slot gives double HTML #144

Closed wbern closed 6 years ago

wbern commented 6 years ago

Works

<mybd-message message="success">
        <div vue-slot="text">
            Hello world
        </div>
    </mybd-message>

.vue file / custom element

<template>
    <div class="alert alert_animated">
        <span class="alert__icon"></span>
        <span class="alert__text">
            <slot name="text" />
        </span>
    </div>
</template>

This works.

Not working / double output:

<mybd-message message="success">
            Hello world
    </mybd-message>

.vue file / custom element

<template>
    <div class="alert alert_animated">
        <span class="alert__icon"></span>
        <span class="alert__text">
            <slot />
        </span>
    </div>
</template>

Output:

<mybd-message
    message="success"
    vce-ready=""
>
    <div class="alert alert_animated"><span class="alert__icon"></span> <span
            class="alert__text">
            <div class="alert alert_animated"><span class="alert__icon"></span>
                <span class="alert__text"><span>Hello world</span></span></div>
        </span></div>
</mybd-message>

Workaround: use vue-slot ( named slots ).

Notes:

wbern commented 6 years ago

After a little more research, it seems this happens when I

  1. Render the custom element
  2. Stop rendering the custom element (angularjs 1.x template compositioning, some ng-if)
  3. Render the custom element again.

Upon second render, the content will be double.

It might be happening because of this line.

if (vueVersion >= 2) {
      var elementOriginalChildren = element.cloneNode(true).childNodes; <- contains the entire custom-element, not just the children.
karol-f commented 6 years ago

Hi, due to implementation, non-wrapped content passed to slots (like "Hello World" in <mybd-message message="success">Hello world</mybd-message>, is wrapped using <span>.

Currently it works like that and have low priority in TODO list. But PR's are welcome! The line needed to be adjust is https://github.com/karol-f/vue-custom-element/blob/373d59fdf03cbfcf2b45f7a32fe31e9c2238919d/src/utils/slots.js#L74

Regards!

wbern commented 6 years ago

@karol-f This still happens even if I wrap with \

-tags.

However, I'm starting to think that angularjs is using a cached element with the rendered content from last render.

karol-f commented 6 years ago

@wbern Hi, as you can see in https://codesandbox.io/s/wmz0mxn9l - when you wrap slot content (in this case <div class="wrapper">) you end up with no <span> element but provided wrapper.

Regards.