最近大屏组件内要新增一个组件:画布组件,可以把另一个大屏的组件渲染到其中。思路是,既然预览的时候可以在弹框内可以把大屏渲染出来,那就可以在指定的组件内渲染出来。
弹框预览代码:(AbsRun 是预览组件)
<dialog>
<AbsRun :id='id'></AbsRun>
</dialog>
我设想的画布组件代码:
<div id='canvas-panel'>
<AbsRun :id="id"></AbsRun>
</div>
运行后发现报错:
看上面的报错,梳理的好久才发现产生了组件循环引用:
首先画布组件需要使用 AbsRun 组件,所以代码如下:
// 画布组件
import AbsRun from '../abs-run.vue'
components:{
AbsRun,
}
AbsRun 组件是预览的,所以又得需要注册所有的组件,当然包括画布组件:
import xxx from '../components/xxx.vue'
import CanvasPanel from '../components/canvas-panel.vue'
components:{
xxx,
CanvasPanel,
}
至此就产生了循环引用问题,那如何解决呢?
为了解释这里发生了什么,我们先把两个组件称为 A 和 B。模块系统发现它需要 A,但是首先 A 依赖 B,但是 B 又依赖 A,但是 A 又依赖 B,如此往复。这变成了一个循环,不知道如何不经过其中一个组件而完全解析出另一个组件。为了解决这个问题,我们需要给模块系统一个点,在那里“A 反正是需要 B 的,但是我们不需要先解析 B。”
在我们的例子中,把 <tree-folder> 组件设为了那个点。我们知道那个产生悖论的子组件是 <tree-folder-contents> 组件,所以我们会等到生命周期钩子 beforeCreate 时去注册它:
beforeCreate: function () {
this.$options.components.TreeFolderContents = require('./tree-folder-contents.vue').default
}
或:
components: {
TreeFolderContents: () => import('./tree-folder-contents.vue')
}
那在我的这种场景下,画布组件就是产生悖论的子组件,所以等到生命周期钩子 beforeCreate 时再去注册 AbsRun:
beforeCreate(){
this.$options.components.AbsRun = () => import('../abs-run')
},
参考: