Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue: root element content and content distribution slots

Tags:

vue.js

vuejs2

In the Vue documentation of the template option for the Vue constructor it is stated, that content of the root element is not displayed "unless content distribution slots are present in the template". However when trying to write something like:

new Vue({
  el: '#app',
  template: `
    <div>
      <h1>App title</h1>
      <slot></slot>
    </div>
  `
});
<html>

<body>
  <div id="app">
    App content
  </div>
  <script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
</body>

</html>

The content from the root element is not included, what is the right way to do it?

Or what is the suggested way to inject additional content programmatically when creating the vue instance?

like image 530
u.dev Avatar asked Mar 01 '18 09:03

u.dev


1 Answers

In some aspects, the root does not behave like a regular component: you can't pass props, nor use <slot>s directly in its template (related: vue/#4485).

Have a look at the current source: the $slots are resolved by the resolveSlots function, and at the point resolveSlots is called on the root component its $options._renderChildren is undefined, so no slots are resolved. Not that it matters after that point, but, effectivelly, the root component never populates its $options._renderChildren.

It's been said that the <slot> handling logic complicates things a bit, so that probably was a design decision.

Alternative solution

The pattern commonly used to handle what you are asking is just wrapping the content in another component (say <app>) component and going from there.

Vue.component('app', {
  template: `<div>
    <h2>I'm the &lt;app&gt; component title</h2>
    <slot>app slot default text</slot>
  </div>`
});
new Vue({
  el: '#app'
});
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<div id="app">
  <app>
    I'm the contents of app's template and was declared in root
  </app>
</div>

See how this.$slots is not populated for root even though it has <slot>s in the demo below.

Vue.component('app', {
  template: `<div>
    <h2>I'm the &lt;app&gt; component title</h2>
    <slot>app slot default text</slot>
  </div>`,
  created() {
    console.log("<app>'s VDOM children (LENGTH): ", this.$options._renderChildren.length);
    console.log("<app>'s slots (LENGTH): ", this.$slots.default.length);
  }
});
new Vue({
  el: '#app',
  created() {
    console.log("root's VDOM children: ", this.$options._renderChildren);
    console.log("root's slots: ", this.$slots);
  }
});
<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
<div id="app">
  <app>
    I'm the contents of app's template
  </app>

  <slot>root's slot's default content, won't make it into $slots, check the console</slot>
</div>
like image 156
acdcjunior Avatar answered Nov 13 '22 10:11

acdcjunior