注意:首先它可能看起来像是多次回答,但我觉得我的情况有所不同。
多次使用<slot>
时,我收到以下错误。
在同一个渲染树中找到重复出现的插槽“default” - 这可能会导致渲染错误。
有使用Scoped Slots
的解决方案,但据我所知,与v-for
一起使用是很好的。我不确定,我可能错了,如果我是,请告诉我:)。
我遇到需要多次在子组件中复制静态内容(带标记)的情况。
// Parent Component
<template>
<child-comp>
<h1>Lorem Ipusm</h1>
<button @click="fnDoSomething">Yahoo!<button>
// ... there will be lot more lines of markups that will go here in default slot
<child-comp>
<template>
// Child Component
<template>
<div>
<h2>Need one default slot here</h2>
<slot><slot>
<div>
<h2>Need one more default slot here</h2>
<slot><slot>
<div>
</div>
<template>
如果我不能解决上述问题或vue.js的限制,那么请帮助我,让我知道如何克隆插槽(或类似的东西),它仍然是被动的。
答案 0 :(得分:2)
使用render function应该能够实现您的需求,如下面的演示:
但是你可能遇到一些像这个链接的麻烦:Why are duplicated slots bad?。
来自Vue.js核心团队的开发人员说:
Vue会重用相同的vnode对象(代表元素) 在实际创建DOM元素期间多次。
问题在于每个vnode都会获得对它的引用 相应的DOM元素集。
如果多次重复使用相同的vnode对象,这些引用 得到覆盖,你最终得到没有的DOM元素 虚拟dom中的表示,或引用错误的vnode 元件。
因此在下面的演示中,当您单击该按钮时,您会发现第一个案例的第一个插槽未同步(VNode被覆盖)。
如果您的默认插槽是完全静态内容,则不绑定到任何属性和方法,则可以在render()中使用多个默认插槽。但如果没有,你必须使用范围插槽来实现你需要的东西。
或者你可以深度克隆 this.$slots.default
(检查VNode constructor),它将避免被覆盖的问题。 (查看以下演示中的第三种情况)
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>