javascript - 如何解决 - 在同一渲染树中发现重复的插槽“默认”存在
问题描述
<slot>
多次使用时出现以下错误:
在同一渲染树中发现重复的插槽“默认”存在 - 这可能会导致渲染错误。
有一些使用“作用域插槽”的解决方案,但我的理解是使用v-for
. 我不确定,我可能错了,如果我错了,请告诉我。
我有一种情况,我需要在子组件中多次复制静态内容(带有标记)。
父组件:
<template>
<child-comp>
<h1>Lorem Ipusm</h1>
<button @click="fnDoSomething">Yahoo!<button>
<!-- ... there will be a lot more that will go here in the default slot -->
<child-comp>
<template>
子组件:
<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 的限制,那么请告诉我如何克隆插槽(或类似的东西)并让它仍然是响应式的。
解决方案
使用渲染函数应该能够实现你需要的东西,就像下面的演示:
但是你可能会遇到一些麻烦,比如这个链接描述的:为什么重复的插槽不好?.
正如 Vue.js 核心团队的开发者所说:
在 DOM 元素的实际创建过程中,Vue 会多次重复使用相同的 vnode 对象(代表元素)。
这样做的问题是每个 vnode 都获得了对其相应 DOM 元素集的引用。
如果您多次重复使用相同的 vnode 对象,这些引用将被覆盖,并且您最终会得到在虚拟 dom 中没有表示的 DOM 元素,或者引用错误元素的 vnode。
所以在下面的demo中,当你点击按钮时,你会发现第一个case的第一个slot没有同步(VNode被覆盖)。
如果您的默认插槽是完全静态的内容,则不绑定到任何属性和方法,那么在 render() 中使用多个默认插槽应该是可以的。但如果没有,您必须使用作用域插槽来实现您所需要的。
或者您可以深度克隆 this.$slots.default
(检查VNode 构造函数),它将避免覆盖问题。(检查下面演示中的第三种情况)
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>
推荐阅读
- c++ - 如何在二叉树中有效地找到路径?
- vis.js-timeline - vis.js : 改变可见项目的类
- python - 将输出打印到 cmd
- node.js - Node.js:无法使用 TCP/IP 连接 UPOS 财务打印机
- python - 如何根据python中的标签按输出分组
- seo - PWA 应用程序是否出现在谷歌搜索结果中?
- oracle - ORA-01427: 单行子查询在 oracle 中返回多于一行
- visual-studio-code - Visual Studio 代码中的 Intelephence 扩展无法识别 Drupal 7 函数:大量未定义函数警告
- javascript - 为什么我收到此错误:React Hook useEffect 内部的变量在每次渲染后都会丢失?
- flutter - 错误:未处理的异常:类型'_InternalLinkedHashMap
' 不是类型 'Iterable 的子类型 '