组件之间的循环引用

点击打开视频讲解更详细

假设你需要构建一个文件目录树,像访达或资源管理器那样的。你可能有一个 <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 //使用ElementUI
Vue.use(ElementUI) // Vue.use(Plugin1,'参数1') // Vue.use(Plugin2,'参数2') new Vue({
render: h => h(App),
}).$mount('#app')

若对您有帮助,请点击跳转到B站一键三连哦!感谢支持!

054_末晨曦Vue技术_处理边界情况之组件之间的循环引用的更多相关文章

  1. 048_末晨曦Vue技术_处理边界情况之使用$root访问根实例

    处理边界情况之使用$root访问根实例 点击打开视频教程 在每个 new Vue 实例的子组件中,其根实例可以通过 $root property 进行访问. 例如,在这个根实例中: src\main. ...

  2. 056_末晨曦Vue技术_处理边界情况之X-template

    处理边界情况之X-template 点击打开视频讲解更加详细 另一个定义模板的方式是在一个<script>元素中,并为其带上 text/x-template 的类型,然后通过一个 id 将 ...

  3. 051_末晨曦Vue技术_处理边界情况之provide和inject依赖注入

    provide和inject依赖注入 点击打开视频讲解更详细 在此之前,在我们描述访问父级组件实例的时候,展示过一个类似这样的例子: <google-map> <google-map ...

  4. 057_末晨曦Vue技术_处理边界情况之强制更新($forceUpdate)与通过 v-once 创建低开销的静态组件

    强制更新($forceUpdate) 点击打开视频讲解更加详细 在vue中,如果data中有基本数据类型变量:age,修改他,页面会自动更新. 但如果data中的变量为数组或对象(引用数据类型),我们 ...

  5. 057_末晨曦Vue技术_处理边界情况之强制更新和创建低开销的静态组件

    强制更新和创建低开销的静态组件 点击打开视频讲解更加详细 强制更新 如果你发现你自己需要在 Vue 中做一次强制更新,99.9% 的情况,是你在某个地方做错了事. 你可能还没有留意到数组或对象的变更检 ...

  6. 052_末晨曦Vue技术_处理边界情况之程序化的事件侦听器

    程序化的事件侦听器 点击打开视频讲解更详细 现在,你已经知道了 $emit 的用法,它可以被 v-on 侦听,但是 Vue 实例同时在其事件接口中提供了其它的方法.我们可以: 通过 $on(event ...

  7. 066_末晨曦Vue技术_过渡 & 动画之多个元素的过渡

    多个元素的过渡 点击打开视频讲解更加详细 我们之后讨论多个组件的过渡,对于原生标签可以使用 v-if/v-else.最常见的多标签过渡是一个列表和描述这个列表为空消息的元素: <transiti ...

  8. 058_末晨曦Vue技术_过渡 & 动画之过渡的类名

    进入/离开 & 列表过渡 点击打开视频讲解更加详细 概述 Vue 在插入.更新或者移除 DOM 时,提供多种不同方式的应用过渡效果.包括以下工具: 在 CSS 过渡和动画中自动应用 class ...

  9. Vue(基础四)_总结五种父子组件之间的通信方式

    一.前言 这篇文章主要总结了几种通信方式: 1.方式一:使用props: [ ]和$emit()  (适用于单层通信) 2.方式二:$attrs和$listeners(适用于多层) 3.方式三:中央处 ...

随机推荐

  1. VTK 截图

    vtk的vtkRenderWindowInteractor中的Initialize函数初始化了可交互的窗口,但是实际工程中,往往需要把窗口拿出来在别的页面上显示,如存为png图片等等.本文主要介绍如何 ...

  2. 数字化转型之数字资产知识库(springboot+es+vue+neo4j)

    前言 在数字化高度普及的时代,企事业机关单位在日常工作中会产生大量的文档,例如医院制度汇编,企业知识共享库等.针对这些文档性的东西,手工纸质化去管理是非常消耗工作量的,并且纸质化查阅难,易损耗,所以电 ...

  3. Python基础学习_03

    程序的流程控制 1.程序的组织结构 (1)顺序结构 (2)选择结构 (3)循环结构 2.对象的布尔值 以下对象的布尔值为False False,数值0,None,空字符串,空列表,空元组,空字典,空集 ...

  4. React.js中JSX的原理与关键实现

    在开始开发之前,我们需要创建一个空项目文件夹.安装 初始化 npm init -y 2.安装webpack相关依赖 npm install webpack webpack-cli -D 安装babel ...

  5. CompletableFuture的入门

    runAsync 和 supplyAsync runAsync接受一个Runable的实现,无返回值 CompletableFuture.runAsync(()->System.out.prin ...

  6. Python: list列表的11个内置方法

    先来逼逼两句: 在实际开发中,经常需要将一组(不只一个)数据存储起来,以便后边的代码使用.在VBA中有使用数组,可以把多个数据存储到一起,通过数组下标可以访问数组中的每个元素.Python 中没有数组 ...

  7. NC20032 [HNOI2003]激光炸弹

    NC20032 [HNOI2003]激光炸弹 题目 题目描述 一种新型的激光炸弹,可以摧毁一个边长为R的正方形内的所有的目标. 现在地图上有 \(n\) (\(N ≤ 10000\))个目标,用整数 ...

  8. JDBCToolsV3 :DAO

    编写文件和步骤 ①,bean模块:数据类Course,包含数据的class,封装数据类型; ②,DAO:1)定义对数据的操作接口,及规定标准(包含怎样的操作).例如:CourseDAO数据库操作的接口 ...

  9. python解决“failed to execute pyi_rth_pkgres”问题

    pip uninstall pyinstaller pip install https://github.com/pyinstaller/pyinstaller/archive/develop.zip

  10. 牛客SQL刷题第三趴——SQL大厂面试真题

    01 某音短视频 SQL156 各个视频的平均完播率 [描述]用户-视频互动表tb_user_video_log.(uid-用户ID, video_id-视频ID, start_time-开始观看时间 ...