Vue3子组件访问$slot数据触发循环结构转JSON错误
Vue3模板打印插槽对象触发循环引用错误的解决办法
问题根源
在模板里写<pre>{{ $slots.title() }}</pre>时,Vue会尝试把插槽返回的VNode对象转成JSON字符串展示,但VNode内部包含父节点、上下文这类循环引用的属性,直接序列化就会触发TypeError: Converting circular structure to JSON。而在<script>里用console.log能正常输出,是因为浏览器控制台会自动处理循环引用的展示。
可行解决方案
1. 直接取插槽文本内容(纯文本插槽适用)
如果你的title插槽只传了纯文本,直接访问VNode的children就能拿到内容:
<pre>{{ $slots.title()[0].children }}</pre>
2. 在脚本里处理插槽结构,提取有用信息
要是想查看完整的插槽结构,先在<script setup>里用useSlots获取插槽,然后提取非循环引用的属性,再放到模板里展示:
<script setup> import { defineProps, defineEmits, useSlots } from 'vue' const props = defineProps({ btnStyle: String, }) const emit = defineEmits(['close']) const slots = useSlots() // 过滤掉会导致循环引用的属性 const formatSlotInfo = () => { const titleSlot = slots.title?.() || [] return titleSlot.map(vnode => ({ 类型: vnode.type, 内容: vnode.children, 属性: vnode.props })) } const slotInfo = formatSlotInfo() </script> <template> <teleport to="#modals-container"> <div class="modal z-10 absolute top-0 left-0 w-full h-full p-10 bg-yellow-50"> <h1><slot name="title" /></h1> <slot /> <pre>{{ slotInfo }}</pre> <button :class="btnStyle" @click="$emit('close')">Hide modal</button> </div> </teleport> </template>
3. 用JSON.stringify的replacer跳过循环引用属性
直接在模板里用JSON.stringify配合替换函数,跳过那些会引发循环引用的属性:
<pre>{{ JSON.stringify($slots.title(), (key, value) => { // 忽略parent、ctx这类循环引用属性 if (key === 'parent' || key === 'ctx') return undefined return value }, 2) }}</pre>
关于移除()后输出无意义的说明
去掉()后,$slots.title是一个函数引用,模板里直接展示的是函数的字符串形式(比如function() { [native code] }),自然没意义。课程视频里的输出应该是在脚本中打印,或者做了专门的处理,和模板直接展示的逻辑不一样。
内容的提问来源于stack exchange,提问作者Leon Gaban
相关产品推荐
相关产品推荐

