动态组件和插槽

[Vue2]动态组件和插槽

动态组件和插槽来实现外部传入自定义渲染

组件

<template><!-- 回复的处理进度 --><div v-if="steps.length > 0" class="gain-box-header"><el-steps direction="vertical"><div class="load-but"><el-step v-for="item in steps" :key="item.id" :icon="getIcon(item)"><div slot="title" class="step_title" @click="item.isShow = !item.isShow"><div>{{ item.title || '加载中' }}</div><div><i v-if="item.isShow" class="el-icon-arrow-down"></i><i v-else class="el-icon-arrow-up"></i></div></div><template slot="description"><div v-show="item.isShow"><!-- 内置类型渲染 --><template v-if="item.type === NormalSteps.Markdown"><MdRender v-if="item.content" :content="item.content" /></template><template v-else-if="item.type === NormalSteps.Text"><div class="step_label">{{ item.content }}</div></template><template v-else-if="item.type === SpecialStep.RxtPolicyList"><div class="step_label">{{ item.content }}</div></template><!-- 自定义组件渲染 --><template v-else-if="isCustomComponent(item.type)"><component :is="getCustomComponent(item.type)" :item="item" :content="item.content":meta="item.meta"v-bind="item.props || {}"/></template><!-- 自定义插槽渲染 --><template v-else-if="isCustomSlot(item.type)"><slot :name="getSlotName(item.type)":item="item":content="item.content":meta="item.meta"><!-- 插槽默认内容 --><div class="step_label">{{ item.content }}</div></slot></template><!-- 自定义渲染函数 --><template v-else-if="isCustomRender(item.type)"><div v-html="getCustomRender(item.type, item)"></div></template><!-- 默认文本渲染 --><template v-else><div class="step_label">{{ item.content }}</div></template></div></template></el-step></div></el-steps></div>
</template><script>
import MdRender from '@/components/MdRender/think'
import { NormalSteps, SpecialStep } from '@/dicts/DictSse.js'export default {name: 'StepList',components: { MdRender },props: {steps: {type: Array,default: () => [// {//   id: '', // 唯一键//   type: 'md', // 类型//   title: '', // 标题//   content: '', // 内容//   isStop: false, // 是否结束//   isShow: true, // 是否展示//   isError: false, // 是否失败 消息停止时改步骤未结束,则标记为失败//   meta: {}, // 附加属性//   props: {}, // 传递给自定义组件的额外props// }]},// 自定义组件映射 { 'custom-chart': ChartComponent }customComponents: {type: Object,default: () => ({})},// 自定义渲染函数映射 { 'custom-render': (item) => '<div>...</div>' }customRenders: {type: Object,default: () => ({})}},data() {return {NormalSteps,SpecialStep}},methods: {// 判断使用的icongetIcon(item) {if (!item.isStop) {return 'el-icon-loading'}if (item.isError) {return 'el-icon-error'}return 'el-icon-success'},// 判断是否为自定义组件isCustomComponent(type) {return type && type.startsWith('component:') && this.customComponents[type.replace('component:', '')]},// 获取自定义组件getCustomComponent(type) {const componentName = type.replace('component:', '')return this.customComponents[componentName]},// 判断是否为自定义插槽isCustomSlot(type) {return type && type.startsWith('slot:')},// 获取插槽名称getSlotName(type) {return type.replace('slot:', '')},// 判断是否为自定义渲染函数isCustomRender(type) {return type && type.startsWith('render:') && this.customRenders[type.replace('render:', '')]},// 获取自定义渲染结果getCustomRender(type, item) {const renderName = type.replace('render:', '')const renderFn = this.customRenders[renderName]return renderFn ? renderFn(item) : item.content}}
}
</script><style scoped>
.gain-box-header {width: 100%;display: flex;align-items: center;
}.load-but {width: 100%;padding: 15px 10px;background: rgba(13, 62, 135, 0.06);border-radius: 17px;border: 1px solid rgba(1, 128, 255, 0.03);
}
.load-but > span {line-height: 29px;color: #625b88;
}.step_title {display: flex;align-items: center;justify-content: space-between;
}.step_label {white-space: pre-wrap;font-size: 0.75rem;color: #606266;
}::v-deep .el-steps {width: 100%;
}::v-deep .el-step {min-height: 50px;
}::v-deep .el-step:last-child {min-height: 0;
}::v-deep .el-step__icon.is-icon {background: transparent;
}::v-deep .el-step.is-vertical .el-step__title {font-size: 14px;color: #222222;
}::v-deep .el-step.is-vertical .el-step__line {top: 27px;bottom: 3px;
}::v-deep .el-icon-success {color: #4281ed;
}::v-deep .el-icon-error {color: #c0c4cc;
}::v-deep .vuepress-markdown-body {background: transparent;
}
</style>

外部引用

<template><div><!-- 使用StepList组件 --><StepList :steps="steps" :custom-components="customComponents":custom-renders="customRenders"><!-- 自定义插槽渲染 --><template #custom-table="{ item, content, meta }"><el-table :data="content" size="mini" border><el-table-column prop="name" label="名称" /><el-table-column prop="value" label="" /></el-table></template><template #custom-progress="{ item, meta }"><el-progress :percentage="meta.progress" :status="meta.status":stroke-width="8"/><div style="margin-top: 8px; font-size: 12px; color: #666;">{{ meta.progressText }}</div></template><template #custom-image="{ item, content }"><div class="image-container"><img :src="content" :alt="item.title" style="max-width: 100%; height: auto;" /></div></template></StepList></div>
</template><script>
import StepList from './StepList.vue'
import { NormalSteps, SpecialStep } from '@/dicts/DictSse.js'// 自定义图表组件
const CustomChart = {props: ['item', 'content', 'meta'],template: `<div class="custom-chart"><div class="chart-title">{{ item.title }}</div><div class="chart-content"><div v-for="(data, index) in content" :key="index" class="chart-bar"><span class="bar-label">{{ data.label }}</span><div class="bar-container"><div class="bar-fill" :style="{ width: data.value + '%' }"></div></div><span class="bar-value">{{ data.value }}%</span></div></div></div>`,style: `.custom-chart { padding: 10px; }.chart-title { font-weight: bold; margin-bottom: 10px; }.chart-bar { display: flex; align-items: center; margin-bottom: 8px; }.bar-label { width: 80px; font-size: 12px; }.bar-container { flex: 1; height: 20px; background: #f0f0f0; margin: 0 10px; position: relative; }.bar-fill { height: 100%; background: #409eff; transition: width 0.3s; }.bar-value { font-size: 12px; }`
}// 自定义列表组件
const CustomList = {props: ['item', 'content', 'meta'],template: `<div class="custom-list"><div v-for="(listItem, index) in content" :key="index" class="list-item"><div class="list-icon"><i :class="listItem.icon || 'el-icon-check'"></i></div><div class="list-content"><div class="list-title">{{ listItem.title }}</div><div class="list-desc">{{ listItem.description }}</div></div></div></div>`,style: `.custom-list { padding: 10px 0; }.list-item { display: flex; align-items: flex-start; margin-bottom: 12px; }.list-icon { width: 20px; height: 20px; margin-right: 10px; display: flex; align-items: center; justify-content: center; }.list-content { flex: 1; }.list-title { font-weight: bold; margin-bottom: 4px; }.list-desc { font-size: 12px; color: #666; }`
}export default {name: 'StepListExample',components: { StepList },data() {return {// 自定义组件映射customComponents: {'chart': CustomChart,'list': CustomList},// 自定义渲染函数映射customRenders: {'highlight': (item) => {return `<div style="background: #fff3cd; padding: 10px; border-radius: 4px; border-left: 4px solid #ffc107;"><strong>⚠️ 重要提示</strong><br/>${item.content}</div>`},'code': (item) => {return `<pre style="background: #f8f9fa; padding: 12px; border-radius: 4px; overflow-x: auto;"><code>${item.content}</code></pre>`}},// 步骤数据steps: [// 内置类型 - Markdown{id: '1',type: NormalSteps.Markdown,title: '步骤1:分析数据',content: '## 数据分析结果\n\n- 处理了 **1000** 条记录\n- 发现 `5` 个异常值\n- 准确率达到 **95%**',isStop: true,isShow: true,isError: false,meta: {}},// 内置类型 - Text{id: '2',type: NormalSteps.Text,title: '步骤2:文本说明',content: '这是一个普通的文本说明内容,用于展示基本的文本渲染效果。',isStop: true,isShow: true,isError: false,meta: {}},// 自定义组件 - 图表{id: '3',type: 'component:chart',title: '步骤3:数据可视化',content: [{ label: '成功率', value: 85 },{ label: '处理速度', value: 92 },{ label: '准确率', value: 78 }],isStop: true,isShow: true,isError: false,meta: {},props: {} // 额外传递给组件的props},// 自定义组件 - 列表{id: '4',type: 'component:list',title: '步骤4:任务清单',content: [{ title: '数据预处理', description: '清洗和格式化原始数据',icon: 'el-icon-check'},{ title: '模型训练', description: '使用机器学习算法训练模型',icon: 'el-icon-loading'},{ title: '结果验证', description: '验证模型的准确性和可靠性',icon: 'el-icon-time'}],isStop: false,isShow: true,isError: false,meta: {}},// 自定义插槽 - 表格{id: '5',type: 'slot:custom-table',title: '步骤5:数据表格',content: [{ name: '处理时间', value: '2.5秒' },{ name: '内存使用', value: '128MB' },{ name: 'CPU使用率', value: '45%' }],isStop: true,isShow: true,isError: false,meta: {}},// 自定义插槽 - 进度条{id: '6',type: 'slot:custom-progress',title: '步骤6:处理进度',content: '',isStop: false,isShow: true,isError: false,meta: {progress: 67,status: 'active',progressText: '正在处理中... 67%'}},// 自定义插槽 - 图片{id: '7',type: 'slot:custom-image',title: '步骤7:结果展示',content: 'https://via.placeholder.com/300x200?text=Processing+Result',isStop: true,isShow: true,isError: false,meta: {}},// 自定义渲染函数 - 高亮提示{id: '8',type: 'render:highlight',title: '步骤8:重要提示',content: '请注意:此操作不可逆,请确保数据已备份!',isStop: true,isShow: true,isError: false,meta: {}},// 自定义渲染函数 - 代码块{id: '9',type: 'render:code',title: '步骤9:代码示例',content: `function processData(data) {return data.map(item => ({...item,processed: true,timestamp: new Date().toISOString()}));
}`,isStop: true,isShow: true,isError: false,meta: {}}]}}
}
</script><style scoped>
.image-container {text-align: center;padding: 10px;
}
</style>

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unreal5从入门到精通之如何实现UDP Socket通讯

文章目录 一.前言二.什么是FSocket1. FSocket的作用2. FSocket关键特性三.创建Socket四.数据传输五.线程安全六.UDPSocketComponentUDPSocketComponent.hUUDPSocketComponent.cpp七.SocketTest测试八.最后一.前言 我们在开发UE 的过程中,会经常使用到Socket通讯,包括TCP,UD…

UI前端大数据处理新趋势:基于边缘计算的数据处理与响应

hello宝子们...我们是艾斯视觉擅长ui设计、前端开发、数字孪生、大数据、三维建模、三维动画10年经验!希望我的分享能帮助到您!如需帮助可以评论关注私信我们一起探讨!致敬感谢感恩!一、引言&#xff1a;前端大数据的 “云端困境” 与边缘计算的破局当用户在在线文档中实时协作…

Reading and Writing to a State Variable

本节是《Solidity by Example》的中文翻译与深入讲解&#xff0c;专为零基础或刚接触区块链开发的小白朋友打造。我们将通过“示例 解说 提示”的方式&#xff0c;带你逐步理解每一段 Solidity 代码的实际用途与背后的逻辑。Solidity 是以太坊等智能合约平台使用的主要编程语…

c# 深度解析:实现一个通用配置管理功能,打造高并发、可扩展的配置管理神器

文章目录深入分析 ConfigManager<TKey, TValue> 类1. 类设计概述2. 核心成员分析2.1 字段和属性2.2 构造函数3. 数据加载机制4. CRUD 操作方法4.1 添加数据4.2 删除数据4.3 更新数据4.4 查询数据4.5 清空数据5. 数据持久化6. 设计亮点7. 使用示例ConfigManager<TKey, …

运维打铁: Python 脚本在运维中的常用场景与实现

文章目录引言思维导图常用场景与代码实现1. 服务器监控2. 文件管理3. 网络管理4. 自动化部署总结注意事项引言 在当今的 IT 运维领域&#xff0c;自动化和效率是至关重要的。Python 作为一种功能强大且易于学习的编程语言&#xff0c;已经成为运维人员不可或缺的工具。它可以帮…

【零基础入门unity游戏开发——unity3D篇】3D光源之——unity反射和反射探针技术

文章目录 前言实现天空盒反射1、新建一个cube2、全反射材质3、增加环境反射分辨率反射探针1、一样把小球材质调成全反射2、在小球身上加添加反射探针3、设置静态物体4、点击烘培5、效果6、可以修改反射探针区域大小7、实时反射专栏推荐完结前言 当对象收到直接和间接光照后,它…

React Three Fiber 实现 3D 模型点击高亮交互的核心技巧

在 WebGL 3D 开发中&#xff0c;模型交互是提升用户体验的关键功能之一。本文将基于 React Three Fiber&#xff08;R3F&#xff09;和 Three.js&#xff0c;总结 3D 模型点击高亮&#xff08;包括模型本身和边框&#xff09;的核心技术技巧&#xff0c;帮助开发者快速掌握复杂…

卷积神经网络实战:MNIST手写数字识别

夜渐深&#xff0c;我还在&#x1f618; 老地方 睡觉了&#x1f64c; 文章目录&#x1f4da; 卷积神经网络实战&#xff1a;MNIST手写数字识别&#x1f9e0; 4.1 预备知识⚙️ 4.1.1 torch.nn.Conv2d() 三维卷积操作&#x1f4cf; 4.1.2 nn.MaxPool2d() 池化层的作用&#x1f4…

HarmonyOS应用无响应(AppFreeze)深度解析:从检测原理到问题定位

HarmonyOS应用无响应&#xff08;AppFreeze&#xff09;深度解析&#xff1a;从检测原理到问题定位 在日常应用使用中&#xff0c;我们常会遇到点击无反应、界面卡顿甚至完全卡死的情况——这些都可能是应用无响应&#xff08;AppFreeze&#xff09; 导致的。对于开发者而言&am…

湖北设立100亿元人形机器人产业投资母基金

湖北设立100亿元人形机器人产业投资母基金 湖北工信 2025年07月08日 12:03 湖北 &#xff0c;时长01:20 近日&#xff0c;湖北设立100亿元人形机器人产业投资母基金&#xff0c;重点支持人形机器人和人工智能相关产业发展。 人形机器人产业投资母基金由湖北省财政厅依托省政府…

时序预测 | Pytorch实现CNN-LSTM-KAN电力负荷时间序列预测模型

预测效果 代码主要功能 该代码实现了一个结合CNN&#xff08;卷积神经网络&#xff09;、LSTM&#xff08;长短期记忆网络&#xff09;和KAN&#xff08;Kolmogorov-Arnold Network&#xff09;的混合模型&#xff0c;用于时间序列预测任务。主要流程包括&#xff1a; 数据加…

OCR 识别:车牌识别相机的 “火眼金睛”

车牌识别相机在交通管理、停车场收费等场景中&#xff0c;需快速准确识别车牌信息。但实际环境中&#xff0c;车牌可能存在污渍、磨损、光照不均等情况&#xff0c;传统识别方式易出现误读、漏读。OCR 技术让车牌识别相机如虎添翼。它能精准提取车牌上的字符&#xff0c;不管是…

Java面试基础:面向对象(2)

1. 接口里可以定义哪些方法抽象方法&#xff1a;抽象方法是接口的核心部分&#xff0c;所有实现接口的类都必须实现这些方法。抽象方法默认是 public 和 abstract 修饰&#xff0c;这些修饰符可以省略。public interface Animal {void Sound(); }默认方法&#xff1a;默认方法是…

有哪些更加简洁的for循环?循环语句?

目录 简洁的for循环 循环过程修改循环变量 循环语句 不同编程语言支持的循环语句 foreach 无限循环 for循环历史 break和continue 循环判断结束值 循环标签 循环语句优化 循环表达式返回值 简洁的for循环 如果需要快速枚举一个集合的元素&#xff0c;尽管C语言可以…

RK3568/3588 Android 12 源码默认使用蓝牙mic录音

遇到客户一个需求&#xff0c;如果连接了带mic的蓝牙耳机&#xff0c;默认所有的录音要走蓝牙mic通道。这个功能搞了好久&#xff0c;终于搞定了。1. 向RK寻求帮助&#xff0c;先打通 bt sco能力。此时&#xff0c;还无法默认就切换到蓝牙 mic通道&#xff0c;接下来我们需求默…

解锁HTTP:从理论到实战的奇妙之旅

目录一、HTTP 协议基础入门1.1 HTTP 协议是什么1.2 HTTP 协议的特点1.3 HTTP 请求与响应的结构二、HTTP 应用场景大揭秘2.1 网页浏览2.2 API 调用2.3 文件传输2.4 内容分发网络&#xff08;CDN&#xff09;2.5 流媒体服务三、HTTP 应用实例深度剖析3.1 使用 JavaScript 的 fetc…

uvm_config_db examples

通过uvm_config_db类访问的UVM配置数据库,是在多个测试平台组件之间传递不同对象的绝佳方式。 methods 有两个主要函数用于从数据库中放入和检索项目,分别是 set() 和 get()。 static function void set ( uvm_component cntxt,string inst_name,string …

(C++)任务管理系统(文件存储)(正式版)(迭代器)(list列表基础教程)(STL基础知识)

目录 前言&#xff1a; 源代码&#xff1a; 代码解析&#xff1a; 一.头文件和命名空间 1. #include - 输入输出功能2. #include - 链表容器3. #include - 字符串处理4. using namespace std; - 命名空间 可视化比喻&#xff1a;建造房子 &#x1f3e0; 二.menu()函数 …

Java 中的异步编程详解

前言 在现代软件开发中&#xff0c;异步编程&#xff08;Asynchronous Programming&#xff09; 已经成为构建高性能、高并发应用程序的关键技术之一。Java 作为一门广泛应用于后端服务开发的语言&#xff0c;在其发展过程中不断引入和优化异步编程的支持。从最初的 Thread 和…

MySQL逻辑删除与唯一索引冲突解决

问题背景 在MySQL数据库设计中&#xff0c;逻辑删除&#xff08;软删除&#xff09;是一种常见的实践&#xff0c;它通过设置标志位&#xff08;如is_delete&#xff09;来标记记录被"删除"&#xff0c;而不是实际删除数据。然而&#xff0c;当表中存在唯一约束时&am…