054_末晨曦Vue技术_处理边界情况之组件之间的循环引用
2022-12-25 09:39:29 作者:admin
组件之间的循环引用
点击打开视频讲解更详细
假设你需要构建一个文件目录树,像访达或资源管理器那样的。你可能有一个 <tree-folder>
组件,模板是这样的:
<p> <span>{{ folder.name }}</span> <tree-folder-contents :children="folder.children"/></p>
还有一个 <tree-folder-contents>
组件,模板是这样的:
<ul> <li v-for="child in children"> <tree-folder v-if="child.children" :folder="child"/> <span v-else>{{ child.name }}</span> </li></ul>
当你仔细观察的时候,你会发现这些组件在渲染树中互为对方的后代和祖先——一个悖论!当通过 Vue.component 全局注册组件的时候,这个悖论会被自动解开。如果你是这样做的,那么你可以跳过这里。
然而,如果你使用一个模块系统依赖/导入组件,例如通过 webpack 或 Browserify,你会遇到一个错误:
Failed to mount component: template or render function not defined.
为了解释这里发生了什么,我们先把两个组件称为 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}
或者,在本地注册组件的时候,你可以使用 webpack 的异步 import:
components: { TreeFolderContents: () => import('./tree-folder-contents.vue')}
案例:
<template> <div id="app"> <li v-for="(folder,index) in folders" :key="index"> <HelloWorld :folder="folder"></HelloWorld> </li> </div></template><script>import HelloWorld from './components/HelloWorld.vue'export default { name: 'App', data(){ return { folders: [ { name: '末晨曦吖', children: [{ name: '末晨曦吖 - 1', children: [{ name: '末晨曦吖 - 1 - 1' }] }] }, { name: '满天星辰', children: [{ name: '满天星辰 - 2', children: [{ name: '满天星辰 - 2 - 2' }] }] } ] } }, mounted() { }, components:{ HelloWorld }, methods:{ }}</script><style scoped> </style>
src\components\HelloWorld.vue
<template> <div class="hello"> <span>{{ folder.name }}</span> <Category :children="folder.children"></Category> </div></template><script>import Category from './Category.vue'export default { name: 'HelloWorld', props: ['folder'], //接收的是对象 data(){ return{ } }, mounted(){ }, components:{ Category }, methods:{ }}</script><style scoped></style>
src\components\Category.vue
<template> <div id="app"> <ul> <li v-for="(child,index) in children" :key="index"> <HelloWorld v-if="child.children" :folder="child"></HelloWorld> <span v-else>{{ child.name }}</span> </li> </ul> </div></template><script>// import HelloWorld from './HelloWorld.vue'export default { name: 'Category', props: ['children'], //接收的是数组 data(){ return { name:'Category' } }, // 第二个解决组件之间的循环引用方式 // beforeCreate: function () { // this.$options.components.HelloWorld = require('./HelloWorld.vue').default // }, mounted() { }, components:{ // HelloWorld // 第三个解决组件之间的循环引用方式 HelloWorld: () => import('./HelloWorld.vue') }, methods:{ }}</script><style scoped> </style>
src\main.js
import Vue from 'vue'import App from './App.vue'//引入ElementUI组件库import ElementUI from 'element-ui';//引入ElementUI全部样式import 'element-ui/lib/theme-chalk/index.css';//插件引入// import {Plugin1,Plugin2} from './plugins/plugins.js'// 全局组件注册 // 第一个解决组件之间的循环引用方式// import HelloWorld from './components/HelloWorld'// import Category from './components/Category'// Vue.component('HelloWorld',HelloWorld)// Vue.component('Category',Category)Vue.config.productionTip = false//使用ElementUIVue.use(ElementUI)// Vue.use(Plugin1,'参数1')// Vue.use(Plugin2,'参数2')new Vue({ render: h => h(App),}).$mount('#app')
若对您有帮助,请点击跳转到B站一键三连哦!感谢支持!
猜你喜欢
联络方式:
400-123-789
邮箱:xiachao@163.com
Q Q:12345678
微信公众号
微信二维码