2👍
Use render function should be able to implement what you need like below demo:
But you may meet some troubles like this link decribes: Why are duplicated slots bad?.
As the developer from Vue.js core team said:
Vue would re-use the same vnode objects (which represent elements)
multiple times during the actual creation of the DOM elements.The problem with that is that each vnode gets a reference to its
corresponding DOM element set.If you re-use the same vnode objects multiple times, these references
get overwritten and you end up with DOM elements that have no
representation in the virtual dom, or vnodes that refer to the wrong
element.
So In below demo, when you click the button, you will find the first slot of the first case is not synced (VNode is overwritten).
If your default slot is fully static content then doesn’t bind to any properties and methods, it should be OK to use multiple default slots in render(). But if not, you have to use scoped slot to implement what you need.
Or you can deep clone this.$slots.default
(check VNode constructor), it will avoid the overwritten issue. (check the third case in below demo)
Vue.config.productionTip = false
Vue.component('child', {
render: function (createElement) {
return createElement(
'div',
[
this.$slots.default, // default slot
createElement('div', {
attrs: {
name: 'test'
},
style: {fontSize: '10px', 'color':'green'}
}, this.$slots.default) // default slot
]
)
}
})
function deepClone(vnodes, createElement){
let clonedProperties = ['text','isComment','componentOptions','elm','context','ns','isStatic','key']
function cloneVNode(vnode) {
let clonedChildren = vnode.children && vnode.children.map(cloneVNode)
let cloned = createElement(vnode.tag, vnode.data, clonedChildren)
clonedProperties.forEach(function(item){
cloned[item] = vnode[item]
})
return cloned
}
return vnodes.map( cloneVNode )
}
Vue.component('child2', {
render: function (createElement) {
return createElement(
'div',
[
this.$slots.default, // default slot
createElement('div', {
attrs: {
name: 'test'
},
style: {fontSize: '10px', 'color':'green'}
}, deepClone(this.$slots.default, createElement) ) // default slot
]
)
}
})
Vue.component('child1', {
render: function (createElement) {
return createElement(
'div',
[
this.$slots.default, // default slot
createElement('div', {
attrs: {
name: 'test'
},
style: {fontSize: '10px', 'color':'green'}
}, this.$slots.my) // default slot
]
)
}
})
new Vue({
el: '#app',
data() {
return {
test: {
'item': 'test',
'prop1': 'a'
}
}
},
methods:{
changeData: function() {
this.test.item='none'
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app">
<button @click="changeData()">Click me!!!</button>
<h1 style="background-color:red">Use multiple default slot:</h1>
<child><h1>{{test}}</h1></child>
<h1 style="background-color:red">Use scoped slot instead:</h1>
<child1><h1>{{test}}</h1><template slot="my"><h1>{{test}}</h1></template></child1>
<h1 style="background-color:red">Use Deep Clone (Default) instead:</h1>
<child2><h1>{{test}}</h1><template slot="my"><h1>{{test}}</h1></template></child2>
</div>