How to create Vue.js slot programatically?

2019-02-16 20:20发布

I have the following component with a slot:

<template>
    <div>
        <h2>{{ someProp }}</h2>
        <slot></slot>
    </div>
</template>

For some reasons, I have to manually instantiate this component. This is how I am doing it:

const Constr = Vue.extend(MyComponent);
const instance = new Constr({
    propsData: { someProp: 'My Heading' }
}).$mount(body);

The problem is: I am not able to create slot contents programmatically. So far, I can create simple string based slot:

const Constr = Vue.extend(MyComponent);
const instance = new Constr({
    propsData: { someProp: 'My Heading' }
});

// Creating simple slot
instance.$slots.default = ['Hello'];

instance.$mount(body);

The question is - how can I create $slots programmatically and pass it to the instance I am creating using new?

Note: I am not using a full build of Vue.js (runtime only). So I don't have a Vue.js compiler available to compile the template on the fly.

3条回答
在下西门庆
2楼-- · 2019-02-16 20:26

I think I have finally stumbled on a way to programmatically create a slot element. From what I can tell, the approach does not seem to work for functional components. I am not sure why.

If you are implementing your own render method for a component, you can programmatically create slots that you pass to child elements using the createElement method (or whatever you have aliased it to in the render method), and passing a data hash that includes { slot: NAME_OF_YOUR_SLOT } followed by the array of children within that slot.

For example:

Vue.config.productionTip = false
Vue.config.devtools = false;

Vue.component('parent', {
  render (createElement) {
    return createElement('child', [
      createElement('h1', { slot: 'parent-slot' }, 'Parent-provided Named Slot'),
      createElement('h2', { slot: 'default' }, 'Parent-provided Default Slot')
    ])
  }
})

Vue.component('child', {
  template: '<div><slot name="parent-slot" /><slot /></div>'
})

new Vue({
  el: '#app',
  template: '<parent />'
})
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script>

<div id='app'>
</div>

查看更多
聊天终结者
3楼-- · 2019-02-16 20:40

(This doesn't really answer How to create Vue.js slot programatically?. But it does solve your problem.)

This trick is less hackish compared to using $createElement().

Basically, create a new component that register MyComponent as a local component.

const Constr = Vue.extend({
  template: `
  <MyComponent someProp="My Heading">
    <div>slot here !!!</div>
  </MyComponent>
  `,
  components: {
    MyComponent: MyComponent
  }
});
const instance = new Constr().$mount('#app');

Demo: https://jsfiddle.net/jacobgoh101/shrn26p1/

查看更多
贼婆χ
4楼-- · 2019-02-16 20:42

I looked into TypeScript definition files of Vue.js and I found an undocumented function on Vue component instance: $createElement(). My guess is, it is the same function that is passed to render(createElement) function of the component. So, I am able to solve it as:

const Constr = Vue.extend(MyComponent);
const instance = new Constr({
    propsData: { someProp: 'My Heading' }
});

// Creating simple slot
const node = instance.$createElement('div', ['Hello']);
instance.$slots.default = [node];

instance.$mount(body);

But this is clearly undocumented and hence questionable approach. I will not mark it answered if there is some better approach available.

查看更多
登录 后发表回答