Vue组件递归——组件化开发

Vue组件递归——组件化开发的必备技能! 不知道大家有没遇到过这样的场景:渲染列表数据的时候,列表的子项还是列表。如果层级少尚且可以用几个for循环搞定,但是层级多或者层级不确定就有点无从下手了。 其实这就是树形结构数据,像常见的组织架构图,文件夹目录,导航菜单等都属于这种结构。很多组件库都带有树形组件,但往往样式不是我们想要的,改起来也非常的费劲。那么,如何自己渲染这些数据呢?答案就是——组件递归! 阅读详情

前言

不知道大家有没遇到过这样的场景:渲染列表数据的时候,列表的子项还是列表。如果层级少尚且可以用几个for循环搞定,但是层级多或者层级不确定就有点无从下手了。

其实这就是树形结构数据,像常见的组织架构图,文件夹目录,导航菜单等都属于这种结构。很多组件库都带有树形组件,但往往样式不是我们想要的,改起来也非常的费劲。那么,如何自己渲染这些数据呢?答案就是——组件递归!
在这里插入图片描述

使用组件递归,并加入简单交互的展示效果。点击节点会在控制台输出节点对应的数据,如果有子节点,则会展开或收起子节点。接下来我们就看看如何实现以上效果吧!

渲染完整数据

渲染数据这一步非常简单,首先是把树形结构封装成一个列表组件,其次判断每一项有没有子节点,如果有子节点,再使用自身组件去渲染就可以了。

src/components/myTree.vue

<template>
  <div class="tree-item">
    <div v-for="item in treeData" :key="item.id">
      <div class="item-title">{{ item.name }}</div>
      <div v-if="item.children && item.children.length" class="item-childen">
        <my-tree :treeData="item.children"></my-tree>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'myTree',
  props: {
    treeData: {
      type: Array,
      default: () => []
    }
  }
}
</script>

<style lang="scss" scoped>
.tree-item {
  .item-title {
    padding: 4px 8px;
  }
  .item-childen {
    padding-left: 20px;
  }
}
</style>

src/App.vue

<template>
  <my-tree :tree-data="treeData"></my-tree>
</template>

<script>
const treeData = [
  { id: 1, name: '一级1' },
  {
    id: 2,
    name: '一级2',
    children: [
      { id: 3, name: '二级2-1' },
      { id: 4, name: '二级2-2' }
    ]
  },
  {
    id: 5,
    name: '一级3',
    children: [
      {
        id: 6,
        name: '二级3-1',
        children: [
          { id: 7, name: '三级3-1-1' },
          { id: 8, name: '三级3-1-2' }
        ]
      },
      { id: 9, name: '二级3-2' },
      { id: 10, name: '二级3-3' }
    ]
  }
]
import myTree from '@/components/myTree.vue'
export default {
  components: {
    myTree
  },
  data() {
    return {
      treeData: treeData
    }
  }
}
</script>

获取节点数据

接下来我们要做的是,点击节点时在控制台输出对应的数据。首先我们使用 $emit,将一级节点的 item 传递出去,也就是子传父的方法,相信大家都会。

其次是将内层节点的数据传递出去,同样使用子传父的方法,只是我们需要给组件里面的 my-tree 绑定@node-click=“$emit(‘node-click’, $event)”,这样每次子级每次都可以调用父级的 node-click 方法,父级又调用它的父级 node-click 方法,最终调的都是最外层的 node-click 方法,我们只需要在这个过程中,把数据传递过去就可以了。这块有点绕,相信大家多看几遍应该可以看懂。修改如下:

src/components/myTree.vue

<div class="item-title" @click="itemNodeClick(item)">{{ item.name }}</div>
<div v-if="item.children && item.children.length" class="item-childen">
  <my-tree
    :treeData="item.children"
    @node-click="$emit('node-click', $event)"
  ></my-tree>
</div>
...
itemNodeClick(item) {
  this.$emit("node-click", item)
}

src/App.vue

<my-tree :tree-data="treeData" @node-click="nodeClick"></my-tree>
...
nodeClick(val) {
  console.log(val)
}

动态展开收起

这一步的思路是给组件设置一个数组,数组中存放的是当前列表中需要展开的节点的id,当点击节点的时候添加或删除节点id,然后判断每个节点的id在不在这个数组,在则显示子节点,不在则隐藏子节点。

src/components/myTree.vue

<div class="item-title" @click="nodeClick(item)">
  <span>{{ item.name }}</span>
  <span v-if="item.children && item.children.length">
    [{{ isOpen(item.id) ? '-' : '+' }}]
  </span>
</div>
<div
  v-if="item.children && item.children.length"
  v-show="isOpen(item.id)"
  class="item-childen"
>
  <my-tree
    :treeData="item.children"
    @node-click="$emit('node-click', $event)"
  ></my-tree>
</div>
...
data() {
  return {
    expandedKeys: [] // 当前列表需要展开的节点id组成的数组
  }
},
methods: {
  nodeClick(item) {
    this.$emit('node-click', item)
    if (item.children && item.children.length) {
      let index = this.expandedKeys.indexOf(item.id)
      if (index > -1) {
        // 如果当前节点id存在数组中,则删除
        this.expandedKeys.splice(index, 1)
      } else {
        // 如果当前节点id不存在数组中,则添加
        this.expandedKeys.push(item.id)
      }
    }
  },
  isOpen(id) {
    // 判断节点id在不在数组中,在则显示,不在则隐藏
    return this.expandedKeys.includes(id)
  }
}

完整代码

src/components/myTree.vue

<template>
  <div class="tree-item">
    <div v-for="item in treeData" :key="item.id">
      <div class="item-title" @click="nodeClick(item)">
        <span>{{ item.name }}</span>
        <span v-if="item.children && item.children.length">
          [{{ isOpen(item.id) ? '-' : '+' }}]
        </span>
      </div>
      <div
        v-if="item.children && item.children.length"
        v-show="isOpen(item.id)"
        class="item-childen"
      >
        <my-tree
          :treeData="item.children"
          @node-click="$emit('node-click', $event)"
        ></my-tree>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'myTree',
  props: {
    treeData: {
      type: Array,
      default: () => []
    }
  },
  data() {
    return {
      expandedKeys: [] // 当前展开的节点id组成的数组
    }
  },
  methods: {
    nodeClick(item) {
      this.$emit('node-click', item)
      if (item.children && item.children.length) {
        let index = this.expandedKeys.indexOf(item.id)
        if (index > -1) {
          // 如果当前节点id存在数组中,则删除
          this.expandedKeys.splice(index, 1)
        } else {
          // 如果当前节点id不存在数组中,则添加
          this.expandedKeys.push(item.id)
        }
      }
    },
    isOpen(id) {
      // 判断节点id在不在数组中,在则显示,不在则隐藏
      return this.expandedKeys.includes(id)
    }
  }
}
</script>

<style lang="scss" scoped>
.tree-item {
  cursor: pointer;
  .item-title {
    padding: 4px 8px;
    &:hover {
      background: #eee;
    }
  }
  .item-childen {
    padding-left: 20px;
  }
}
</style>

src/App.vue

<template>
  <my-tree :tree-data="treeData" @node-click="nodeClick"></my-tree>
</template>

<script>
const treeData = [
  { id: 1, name: '一级1' },
  {
    id: 2,
    name: '一级2',
    children: [
      { id: 3, name: '二级2-1' },
      { id: 4, name: '二级2-2' }
    ]
  },
  {
    id: 5,
    name: '一级3',
    children: [
      {
        id: 6,
        name: '二级3-1',
        children: [
          { id: 7, name: '三级3-1-1' },
          { id: 8, name: '三级3-1-2' }
        ]
      },
      { id: 9, name: '二级3-2' },
      { id: 10, name: '二级3-3' }
    ]
  }
]
import myTree from '@/components/myTree.vue'
export default {
  components: {
    myTree
  },
  data() {
    return {
      treeData: treeData
    }
  },
  methods: {
    nodeClick(val) {
      console.log(val)
    }
  }
}
</script>
Vue3组件化开发:全局、局部与递归组件核心指南 组件化是现代前端开发的核心理念,它将复杂的用户界面拆分为独立、可复用的代码单元,从而提升代码的可维护性和开发效率。其原理在于通过封装视图、逻辑与样式,构建出清晰的数据流与通信机制。在Vue.js等主流框架中,组件化技术价值显著,是实现高效工程实践的基础。全局组件、局部组件与递归组件是Vue3中关键的组件形态,分别对应不同的应用场景。全局组件适用于如基础UI按钮、输入框等跨应用通用的模块;局部组件则是构建业务模块、实现高内聚低耦合设计的首选;而递归组件专门用于处理树形菜单、嵌套评论等具有自相似结构的数据渲染。 阅读详情

相关推荐

Vue 3 的组件式开发(3)

Vue 3组件库的使用与自定义组件库是前端开发中的重要技能,它有助于提升开发效率,实现代码的复用和模块化。创建项目结构使用Vue CLI或Vite等工具创建一个新的Vue 3项目。然后,根据项目需求创建组件库所需的目录结构,如用于存放组件代码,src/styles用于存放样式文件等。编写组件在目录下编写自定义组件。每个组件都包含HTML模板、JavaScript逻辑和CSS样式。例如,创建一个简单的按钮组件:<template></button><script>props: {

突破编程 2443

vue 递归组件的使用及组件间的数据传递

背景 项目需求 原型图如下 可以添加/删除条件和条件组 添加的条件组和父组件有相同的功能 由此可以判断,这是一个递归组件的调用 规划数据结构 递归类型的数据结构,那么子和父的数据结构是一样的,那我们不难想到父里边带children数组,所以我们大概是这样的数据结构: let parent: { id: 1, ... children: [ { id: 1, ... children: [

qq_41261490的博客 3479

Vue.js组件开发指南

data() {return {

2301_78600126的博客 681

秒懂干货!如何用Vue组件递归形成链式层级~

当有一组数据,有层层嵌套的关系(item.child),如何渲染在页面上呢 list: [{ label: "AAA", children: [{ label: "AAA-1", children: []}, {label: "AAA-2", children: [{ label: "AAA-2-1", children: []}, {label: "AAA-2-2", children: []}, { label: "AAA-2-3", children: []}]}, {

hj0556的博客 1059

Vue3组件化开发与Composition API实战指南

组件化开发是现代前端工程的核心范式,通过将UI拆分为独立可复用的组件单元,大幅提升代码的可维护性和开发效率。Vue3的响应式系统基于Proxy实现,配合Composition API提供了更灵活的逻辑组织方式。在工程实践中,合理的组件通信机制(如props/emits、provide/inject)和状态管理方案(如Pinia)对构建复杂应用至关重要。本文以Vue3的script setup语法和Teleport等新特性为例,详解如何实现动态组件加载、递归组件等高级模式,并分享TypeScript集成和虚拟

weixin_32349561的博客 240

C++控制台实现简单的注册登录

C++控制台实现简单的注册登录 #include<iostream> #include<string> #include <vector> #include <conio.h> void Display();//调用display显示switch()界面 void Register();//注册 void Enter();//登录 using nam...

乔路非 2万+

JS使用Vue自定义组件实现动态多层数据渲染+递归+踩坑

在没有使用打包软件(WebPack,VueCli)的原生环境下使用vue自定义组件 组件名称规则 首先说一下组件名称规则,注册的组件名称用了大写的话在使用时则将大写改为 -大写的小写例如注册的名称 myEle,在使用时则

砷碲 - Shendi 1361

Qt OpenGL 3D 点云数据显示

在Qt中使用OpenGL显示3D点云数据是一个常见的需求,特别是在计算机视觉、机器人学和三维重建等领域。下面我将介绍一个基本的实现方案。

深之JohnChen的专栏 1238

谈谈Vue的递归组件

什么是递归组件 上面这个例子,就是用递归组件实现的。递归组件,顾名思义,就是自己的内部实现又调用自己的组件。比如Vue官方给的treeView的例子,父目录下有子目录,子目录下还有子目录,子子孙孙,无穷尽也。就像俄罗斯套娃。 代码结构大概长下面这样子,需要注意递归组件与一般组件不同的地方是,你需要给组件提供一个name选项,防止Vue编译的时候,将内部调用的Example组件认为是未定义组件,当然,你也可以直接将组件注册未一个全局组件。 // example组件的实现 <template&gt

u010227042的博客 566

全国30米分辨率逐年植被覆盖度(FVC)数据集

植被覆盖度是描述地表植被的重要参数与生态环境的基本指标,在大气圈、土壤圈、水圈和生物圈中都占据着重要的地位,区域及全球范围的植被覆盖度估算对植被及相关领域的研究具有重要意义。往往参照《土壤侵蚀分类分级标准》,将植被覆盖度划分为4个等级:<30%为低覆盖度、30%—45%为中低覆盖度、45%—60%为中覆盖度、>60%为高覆盖度。本数据集包括1986至2022年间,全国植被覆盖度数据,FVC范围值为0-1,数据为浮点型,GeoTIFF格式。NDVImax 和NDVImin分别为区域内最大和最小的NDVI值。

地球资源数据云的官方博客 1965

SolidWorks草图绘制实战:如何用图片参考快速搞定智能小车底板设计

本文详细介绍了在SolidWorks中利用图片参考进行草图绘制的实战方法,以智能小车底板设计为例,帮助设计师快速将概念转化为精准三维模型。通过插入、对齐参考图片并高效描图,结合参数化约束与尺寸驱动,大幅提升设计效率和准确性,尤其适合新手入门与老手优化工作流。

rust6ferris的博客 218

【Vue】Vue框架 之 组件递归

组件递归,简述了vue框架中组件递归的出现场景,使用原理,以及一点注意事项

facial_123的博客 2294

百度百科 X-Bk-Token 算法还原

百度百科 X-Bk-Token 算法还原

自成背后的博客 1万+

vue的组件化开发(组件通信,插槽,递归组件)

1. vue组件的通信:包括子通父,父通子,兄弟通信,祖代与后代通信,vuex全局状态管理。 1.1 父向子通信:props属性和refs属性。 1.1.1props属性: //在子组件中 props:{ age: { type: Number, //父组件传递过来age变量的类型,包括String、Number、Boolean、Array、...

斗师——Ace 963

CAPL未来发展方向展望

通过本文的学习,读者应该对CAPL的未来发展方向有了初步的了解。随着汽车电子系统的不断发展,CAPL也在不断演进,以支持更多的技术和应用场景。希望读者能够通过不断的学习和实践,掌握更多的CAPL技巧,提高自己的开发能力。

闲人编程的博客 1182

微信小程序 - 实现仿小红书轮播图组件功能,类似小红书笔记页面图片展示播放效果,微信小程序仿小红书幻灯片轮播支持视频播放、图片预览,自动适应图片或视频大小可左右滑动切换(小程序精美轮播图,丝滑切换)

微信小程序,轮播图组件,微信小程序仿小红书轮播图,小红书轮播图仿造,微信小程序轮播图,微信小程序幻灯片,微信小程序高仿小红书轮播图实现,小程序实现类似小红书一样的轮播图组件,轮播图插件,精致轮播图,精美丝滑流畅切换的轮播图,轮播图组件,小红薯轮播图,关于小红书的小程序不同数量的轮播图,展示不一样的轮播指示点的实现,微信小程序仿小红书图片轮播,开发微信小程序模仿小红书,高仿小红书Banner的指示器,小红书小程序笔记详情轮播图指示点的随图片数量的变化动态变化,微信小程序swiper轮播图,js轮播图,html

✅ 精选推荐文章 6928

Vue3组件化开发:全局、局部与递归组件的实战指南

组件化是现代前端开发的核心思想,它将复杂的用户界面拆分为独立、可复用的代码单元,每个组件封装了自身的结构、样式与逻辑。其原理在于通过模块化降低系统耦合度,实现关注点分离。这一技术价值体现在提升代码可维护性、促进团队协作以及实现高效复用,从而显著提高开发效率。在实际工程中,组件化广泛应用于构建大型单页应用(SPA)、设计系统以及后台管理系统等场景。本文聚焦于Vue3框架下的组件化实践,深入探讨全局组件、局部组件和递归组件这三种关键组织方式。其中,全局组件适用于基础UI库,提供一劳永逸的便利性;局部组件通过精准

weixin_33417488的博客 329

深度解析与实战:长短时记忆网络(LSTM)在股票走势预测中的应用(基于Python + PyTorch)

本文全面探讨了LSTM在股票价格预测中的应用,从理论基础到实践操作。文章首先强调了股票市场预测的重要性,并介绍了LSTM网络结构及其在处理时间序列数据中的优势。接着,详细说明了数据预处理的关键步骤,包括数据收集、清洗、特征选择和归一化。文章还讨论了LSTM模型的构建、训练和评估,并提供了Python及PyTorch的实操案例。最后,总结了LSTM在股票预测的成果,并提出了未来研究的方向,如模型优化和特征工程,旨在帮助读者掌握LSTM在股票价格预测中的应用,并探索提升模型性能的方法。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 2100

Vue组件化开发

Vue组件化开发

m0_54007573的博客 441

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

一、前端-ElementPlus menu菜单无限递归

export default {name: "HomeAside",};

someking的博客 416

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

递归组件实现Element树形Menu菜单

分享一波动态生成侧边栏 并且着重分享一个大坑! 1:模拟菜单数据(开发情况下获取后台数据) const menuList = [ { title: '首页', key: '/home', icon: 'el-icon-s-home' }, { title: '表单', key: '/for...

weixin_43330752的博客 4783

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

Vue 爬坑之路(五)—— 组件进阶

组件(Component)是 Vue.js 最强大的功能之一,之前的文章都只是用到了基本的封装功能,这次将介绍一些更强大的扩展。 一、基本用法 在使用 vue-cli 创建的项目中,组件的创建非常方便,只需要新建一个 .vue 文件,然后在 <template> 中写好 HTML 代码,一个简单的组件就完成了 一个完整的组件,除了 <templat...

a432143的博客 133

antdesign vue 2.0 递归菜单_Vue前端开发——组件篇

业务开发的过程中,经常会进行一些组件化的开发,组件常处理的一般有以下几种全局组件局部组件动态组件递归组件全局组件一般很多地方都会用到的一些功能我们一般封装成全局组件去使用,常规的建立一个全局组件的方法是,公共组件放到components 目录文件下使用Vue.component去注册组件,然后在main.js 中去导入这个公共文件夹// demoimport Vue from "vue";impo...

weixin_39727402的博客 427

vue3树形结构样式

【代码】vue3树形结构样式。

2303_78263863的博客 339

【自学笔记】Vue基础知识点总览-持续更新

Vue.js(读音 /vjuː/,类似于 view)是一个构建用户界面的渐进式JavaScript框架。基于标准HTML、CSS和JavaScript构建,提供了一套声明式的、组件化的编程模型。提示:这里对文章进行总结:例如:以上就是今天要讲的内容,自学记录Vue基础知识点总览。

2301_78806917的博客 935

Vue2组件化开发核心指南:从创建到通信、生命周期与Vue3迁移

组件化开发是现代前端工程化的基石,它通过复用、隔离与清晰边界提升代码可维护性。在Vue2中,组件创建分为全局注册、局部注册与单文件组件,而组件通信则基于props、$emit、v-model等机制实现父子及跨层数据交换。理解组件生命周期是排查数据不同步、状态丢失等疑难问题的关键,动态组件与keep-alive则能优化交互体验与性能。无论是在管理后台、多标签页还是数据大屏中,掌握这些基础能力都能显著降低维护成本。随着Vue3普及,迁移时还需注意多根节点、事件透传、v-model扩展等差异。本文完整梳理Vue2

weixin_42524530的博客 179
上一篇: js实现深拷贝
下一篇: 如何在 JavaScript 中用初始值填充数组
Run4Freedom
博客等级 码龄9年 58粉丝 64原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值