Vue 批量注册组件实现动态组件技巧

介绍

Vue 动态组件的应用场景很多,可应用于动态页签,动态路由等场景,其核心原理是批量注册。在Vue2和Vue3中实现原理相同,只是语法略有差异。

Vue2 实现

基于 webpack

require.context() 是webpack提供的一个自动导入的API
参数1:加载的文件目录
参数2:是否加载子目录
参数3:正则,匹配文件
返回值:导入函数 fn
使用require提供的函数context加载某一个目录下所有的.vue后缀的文件,他的返回值是一个对象,对象里面有一个属keys(), 可以获取所有的文件路径,我们可以遍历importFn.keys(),最后在遍历中使用

首先先描述下应用场景,比如我想在父容器遍历组件集合,根据组件类型(字符串)来首先动态加载组件,如下图:
在这里插入图片描述
如果要是按正常一个个注册的话,也是可以的,就是代码冗余多,不够优雅,所以需要一个方法来实现,这个方法就放到一个JS里去,然后把该index.js直接丢到widget-attr文件夹里.

//index.js
const requireComponent = require.context('./', false, /\w+\.vue$/)
let comps = {}
requireComponent.keys().map(fileName => {
  let comp = requireComponent(fileName).default;
  comps[comp.name] = comp
})
export default comps;

然后在页面引用,如下图:
在这里插入图片描述
好了,到这里简简单单就实现了,我现在整个项目需要这样批量注册的场景也就两三个,所以我在需要批量注册的组件对应的文件夹就放置这个一个index.js就能实现了,如果实际场景不想放那么多,可以自行稍微改造下,传个路径进去,我Vue3版本就是这样实现的

Vue3 实现

基于 Vite

const components = import.meta.glob("./*.vue");
//注意 :  import.meta.glob 不支持变量,

Vue3 使用 组合式 ,方法里也用到了Vite的语法,首页也要把核心代码封装到 dynamicComponents.js里面

详细如下

// utils/dynamicComponents.js
import { defineAsyncComponent } from 'vue';
function loadComponentsFromFolder(folderPath) {
  const components = {};
  let modules = import.meta.glob('@/components/form-designer/widget/*.vue', { eager: false });
  if (folderPath == 'widgetArrt') {
    modules = import.meta.glob('@/components/form-designer/widget/widget-attr/*.vue', { eager: false });
  }
  for (const path in modules) {
    const componentName = path.match(/\/([^/]+)\.vue$/)[1];
    components[componentName] = defineAsyncComponent(modules[path]);
  }
  return components;
}
export default loadComponentsFromFolder;

这个并不完美,理想中应该是根据传参(需要动态注册的组件所在文件夹路径)来实现,但是,如下目前好像并不支持:

// utils/dynamicComponents.js
function loadComponentsFromFolder(folderPath) {
   //省略...
    modules = import.meta.glob(`${folderPath}/*.vue`, { eager: false   });
   //省略...
}
export default loadComponentsFromFolder;

这样写会报错,提示import.meta.glob不支持变量.

[plugin:vite:import-glob] Invalid glob import syntax:
 Expected glob to be a string, but got dynamic template literal
 //大致意思: 只能使用文本,而我们的 path 使用了变量,所以会报错.

这个有其他解决办法,待会下面会说到,因为我在该项目批量注册应用场景不多,所以我就直接传参判断来写死了.
.接下来就是引用了,如下图:
在这里插入图片描述
至此,就实现批量动态注册了,另外注意, 组件集合不要用绑定模式,虽然不报错,但是会报黄提示影响效率

 // let components =ref({})  //不要写成响应式的了,会有性能风险提示
 let components = {} 
 components = loadComponentsFromFolder('widget')

最后

用其他办法来解决这个问题吧,有点复杂,有更好办法的小伙伴可以留言~

使用 fs 模块读取文件列表:
在 Node.js 环境中使用 fs 模块读取指定文件夹下的文件列表。
将文件列表传递给前端,前端再使用 import() 动态导入这些文件。
前端动态导入:

前端根据接收到的文件列表动态导入组件。
实现步骤
1. 后端读取文件列表
首先,在 Vite 项目的 vite.config.js 或者单独的 Node.js 脚本中,使用 fs 模块读取文件列表,并将结果暴露给前端。

javascript
// vite.config.js 或者单独的 Node.js 脚本
const fs = require('fs');
const path = require('path');

function getComponentPaths(folderPath) {
  const baseFolderPath = path.resolve(__dirname, 'src/components/form-designer/widget/');
  const fullFolderPath = folderPath ? path.join(baseFolderPath, folderPath) : baseFolderPath;

  const files = fs.readdirSync(fullFolderPath);
  const componentPaths = files
    .filter(file => file.endsWith('.vue'))
    .map(file => path.join(fullFolderPath, file));

  return componentPaths.map(p => p.replace(/\\/g, '/').replace(path.resolve(__dirname, 'src/'), '@/'));
}

module.exports = {
  getComponentPaths,
};
2. 前端动态导入
在前端,使用 import() 动态导入这些文件。

javascript
// utils/dynamicComponents.js
import { defineAsyncComponent } from 'vue';

const componentCache = {};

async function loadComponentsFromFolder(folderPath) {
  // 检查缓存
  if (componentCache[folderPath]) {
    return componentCache[folderPath];
  }

  // 获取文件路径列表
  const componentPaths = await fetchComponentPaths(folderPath);

  const components = {};

  // 动态导入模块
  await Promise.all(componentPaths.map(async (path) => {
    const componentName = path.match(/\/([^/]+)\.vue$/)[1];
    components[componentName] = defineAsyncComponent(() => import(path));
  }));

  // 缓存结果
  componentCache[folderPath] = components;

  return components;
}

async function fetchComponentPaths(folderPath) {
  // 这里假设你有一个 API 端点来获取文件路径列表
  const response = await fetch(`/api/get-component-paths?folderPath=${folderPath}`);
  const data = await response.json();
  return data.paths;
}

export default loadComponentsFromFolder;
3. 创建 API 端点
在 Vite 项目中创建一个简单的 API 端点来返回文件路径列表。

javascript
// server/index.js
const express = require('express');
const { getComponentPaths } = require('../vite.config');

const app = express();
const port = 3000;

app.get('/api/get-component-paths', (req, res) => {
  const folderPath = req.query.folderPath;
  const paths = getComponentPaths(folderPath);
  res.json({ paths });
});

app.listen(port, () => {
  console.log(`Server running at http://localhost:${port}`);
});
使用示例
在组件或页面中使用 loadComponentsFromFolder 函数时,只需传递不同的 folderPath 参数即可动态注册不同路径下的组件。

javascript
// 在某个 Vue 组件中使用
<script setup>
import { ref, onMounted } from 'vue';
import loadComponentsFromFolder from '@/utils/dynamicComponents';

const folderPath = 'widgetAttr'; // 可以根据实际需求动态设置
const dynamicComponents = ref({});

onMounted(async () => {
  dynamicComponents.value = await loadComponentsFromFolder(folderPath);
});
</script>

<template>
  <div>
    <component v-for="(component, name) in dynamicComponents" :is="component" :key="name"></component>
  </div>
</template>
注意事项
文件路径处理:

确保文件路径在前后端一致,特别是在 Windows 系统中,路径分隔符需要转换。
API 端点:

确保 API 端点能够正确返回文件路径列表。
性能优化:

如果组件数量较多,可以考虑使用懒加载和缓存机制来优化性能。
通过这种方式,你可以根据路径参数动态注册不同文件夹下的组件,而不需要使用 if-else 判断。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/915328.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

WEB攻防-通用漏洞SQL读写注入MYSQLMSSQLPostgraSQL

知识点&#xff1a; 1、SQL注入-MYSQL数据库&#xff1b; 2、SQL注入-MSSQL数据库&#xff1b; 3、SQL注入-PostgreSQL数据库&#xff1b; 首先要找到注入点 详细点&#xff1a; Access无高权限注入点-只能猜解&#xff0c;还是暴力猜解 MYSQL&#xff0c;PostgreSQL&am…

NocoBase 本周更新汇总:提升工作流易用性

汇总一周产品更新日志&#xff0c;最新发布可以前往我们的博客查看。 NocoBase 目前更新包括两个分支&#xff1a;main 和 next 。 main &#xff1a;截止目前最稳定的版本&#xff0c;推荐安装此版本。 next&#xff1a;内测版&#xff0c;包含一些未发布的新特性&#xff…

python高级之面向对象编程

一、面向过程与面向对象 面向过程和面向对象都是一种编程方式&#xff0c;只不过再设计上有区别。 1、面向过程pop&#xff1a; 举例&#xff1a;孩子上学 1. 妈妈起床 2. 妈妈洗漱 3. 妈妈做饭 4. 妈妈把孩子叫起来 5. 孩子起床 6. 孩子洗漱 7. 孩子吃饭 8. 妈妈给孩子送学校…

❤React-React 组件基础(类组件)

❤React-React 组件基础 1、组件化开发介绍 组件化开发思想&#xff1a;分而治之 React的组件按照不同的方式可以分成类组件&#xff1a; 划分方式一&#xff08;按照组件的定义方式&#xff09; 函数组件(Functional Component )和类组件(Class Component)&#xff1b; …

在Java中使用ModelMapper简化Shapefile属性转JavaBean实战

目录 前言 一、原始的处理办法 1、使用Set方法来转换 2、使用构造方法转换 二、基于ModelMapper的动态转换 1、ModelMapper简介 2、集成到项目中 3、Shapefile属性读取 三、总结 前言 在现代软件开发中&#xff0c;尤其是在多层架构中&#xff0c;经常需要将数据从一个…

Arduino IDE Windows 系统 离线安装 esp32 开发板 亲测好用。

1、前提条件需要具备特殊网络。 2、官方文档地址&#xff1a;Installing - - — Arduino ESP32 latest documentation 3、系统&#xff1a;Windows10 Arduino IDE 版本2.3.3 之前安装的esp32开发板的版本是2.0.13&#xff0c;由于之前没有接触过esp32开发&#xff0c;也没…

期权懂|请问如何用期权进行风险管理?

期权小懂每日分享期权知识&#xff0c;帮助期权新手及时有效地掌握即市趋势与新资讯&#xff01; 请问如何用期权进行风险管理&#xff1f; 一、期权可以选择交易活跃的期权合约进行风险管理&#xff1a; 对于初级投资者来说&#xff0c;选择交易活跃的期权合约是非常重要的。…

GNU构建系统和Autotool

1、前言 经常使用Linux的开发人员或者运维人员&#xff0c;可能对configure->make->make install相当熟悉。事实上&#xff0c;这叫GNU构建系统&#xff0c;利用脚本和make程序在特定平台上构建软件。这种方式成为一种习惯&#xff0c;被广泛使用。本文从用户视角和开发…

NLP论文速读|ScPO:自我一致性的偏好优化(Self-Consistency Preference Optimization)

论文速读|Self-Consistency Preference Optimization 论文信息&#xff1a; 简介&#xff1a; 这篇论文试图解决的问题是如何在没有人类标注数据的情况下&#xff0c;提高大型语言模型&#xff08;LLMs&#xff09;在复杂推理任务上的性能。现有的自我对齐技术往往因为难以分配…

【前端学习指南】Vue computed 计算属性 watch 监听器

&#x1f36d; Hello&#xff0c;我是爱吃糖的范同学 &#x1f534; 想把自己学习技术的经历和一些总结分享给大家&#xff01; &#x1f534; 通过这样的方式记录自己成长&#xff0c;同时沉淀自己的技术&#xff0c;我会把所有额外的时间和经历投放到CSDN和公众号&#xff0…

自动驾驶合集(更新中)

文章目录 车辆模型控制路径规划 车辆模型 车辆模型基础合集 控制 控制合集 路径规划 规划合集

vcenter service基本异常处理

服务&#xff1a;vcenter service 版本&#xff1a; 7.0.3 问题描述&#xff1a;无法访问vcenter ui 排障思路&#xff1a; 1. 登入vcenter所在服务器执行基础排查&#xff1a;内存、cpu、磁盘、网络等&#xff0c;发现磁盘日志目录已经爆满&#xff0c;删除180天前的日志恢…

Background Tasks Kit(后台任务开发服务)

11_13日学习笔记 Background Tasks Kit&#xff08;后台任务开发服务&#xff09; Background Tasks Kit简介 设备返回主界面、锁屏、应用切换等操作会使应用退至后台。 应用退至后台后&#xff0c;如果继续活动&#xff0c;可能会造成设备耗电快、用户界面卡顿等现象。 为了…

modbus协议 Mthings模拟器使用

进制转换 HEX 16进制 (0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、F表示0-15) dec 10进制 n(16进制) -> 10 abcd.efg(n) d*n^0 c*n^1 b*n^2 a*n^3 e*n^-1 f*n^-2 g*n^-3&#xff08;10&#xff09; 10 -> n(16进制) Modbus基础概念 高位为NUM_H&…

Python多进程间通讯(包含共享内存方式)

文章目录 1 通过非共享内存配合队列方式2 通过共享内存配合队列方式 注&#xff1a;本博文测试环境为Linux系统。 1 通过非共享内存配合队列方式 下面是一个常见的生产者与消费者的模式示例&#xff0c;这里分别启动了两个子进程&#xff0c;一个为生产者&#xff08;producer…

YOLOv11实战宠物狗分类

本文采用YOLOv11作为核心算法框架&#xff0c;结合PyQt5构建用户界面&#xff0c;使用Python3进行开发。YOLOv11以其高效的特征提取能力&#xff0c;在多个图像分类任务中展现出卓越性能。本研究针对5种宠物狗数据集进行训练和优化&#xff0c;该数据集包含丰富的宠物狗图像样本…

游戏引擎学习第八天

视频参考: https://www.bilibili.com/video/BV1ouUPYAErK/ 理解下面的代码 关于虚函数 代码分解 结构体 foo 的定义&#xff1a; struct foo {int32 X;int64 Y;virtual void Bar(int c); };foo 结构体有两个成员变量&#xff1a;X&#xff08;int32 类型&#xff09;和 Y&…

我要学kali-linux之shell脚本编程1

声明&#xff01; 学习视频来自B站up主 **泷羽sec** 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&a…

尽量通俗易懂地概述.Net U nity跨语言/跨平台相关知识

本文参考来自唐老狮,Unity3D高级编程:主程手记,ai等途径 仅作学习笔记交流分享 目录 1. .Net是什么? 2. .Net框架的核心要点? 跨语言和跨平台 .Net x Unity跨平台发展史 Net Framework 2002 Unity跨平台之 Mono 2004 Unity跨平台之 IL2CPP 2015 二者区别 .NET Core …

大陆 ARS513 / ARS510 标准雷达(解析二)

1。GW_ACU (0x40) • GW_ACU_LongAccel Longitudinal acceleration of ego vehicle. • GW_ACU_LongAccel_ValidFlag Valid flag of signal “GW_ACU_LongAccel”. • GW_ACU_LateralAccel Lateral acceleration of ego vehicle. Signal quality requirements for “GW_ACU_La…