当前位置: 首页 > news >正文

【sgTree】自定义组件:加载el-tree树节点整棵树数据,实现增删改操作。

特性 

  1. 可以自定义主键、配置选项
  2. 支持预定义节点图标:folder文件夹|normal普通样式
  3. 多个提示文本可以自定义
  4. 支持动态接口增删改节点
  5. 可以自定义根节点id
  6. 可以设置最多允许添加的层级深度
  7. 支持拖拽排序,排序过程还可以针对拖拽的节点深度进行自定义限制
  8. 支持隐藏一级节点(根节点)复选框☑
  9. 支持屏蔽一级节点(根节点)勾选☑

sgTree源码 

<template><div :class="$options.name"><div class="tree-header" v-if="!(readonly || readonly === '')"><div class="sg-left"><template v-if="uploadData"><el-tooltippopper-class="sg-el-tooltip":enterable="false"effect="dark":content="`支持拖拽到树上传文件`"placement="top-start"><el-buttontype="text"icon="el-icon-upload"size="mini"@click="(d) => $refs.sgUpload.triggerUploadFile()">批量导入</el-button></el-tooltip><el-button type="text" icon="el-icon-download" size="mini" @click="downloadTpl">下载模板</el-button></template></div><div class="sg-right"><el-button type="text" size="mini" @click.stop="addRoot">{{ (data.text || {}).addRootButtonText || `添加根节点`}}<i class="el-icon-circle-plus-outline"></i></el-button></div></div><div class="tree-container"><el-tree:class="hideRootNodeCheckbox === '' || hideRootNodeCheckbox? 'hideRootNodeCheckbox': ''"ref="tree":data="treeData":node-key="mainKey":props="data.props || {label: 'label', //指定节点标签为节点对象的某个属性值children: 'children', //指定子树为节点对象的某个属性值disabled: 'leaf', //指定节点选择框是否禁用为节点对象的某个属性值isLeaf: 'leaf', //指定节点是否为叶子节点,仅在指定了 lazy 属性的情况下生效}":icon-class="`${data.iconType}-tree-node`":indent="data.indent || 10"@current-change="current_change"@node-click="nodeClick"highlight-current@node-drag-start="nodeDragStart"@node-drag-enter="nodeDragEnter"@node-drag-leave="nodeDragLeave"@node-drag-over="nodeDragOver"@node-drag-end="nodeDragEnd"@node-drop="nodeDrop":draggable="draggable === '' || draggable":allow-drop="allowDrop":allow-drag="allowDrag":show-checkbox="showCheckbox":default-checked-keys="defaultCheckedKeys"@check-change="handleCheckChange"><el-popoverpopper-class="tree-el-popover"placement="right"trigger="hover"title=""content="":disabled="readonly || readonly === ''"slot-scope="{ node, data }"><span class="right"><el-buttontitle="添加"type="text"size=""icon="el-icon-circle-plus-outline"@click.stop="addNode(node, data)"v-if="showAddButton(node)">添加</el-button><el-buttontitle="删除"type="text"size=""icon="el-icon-remove-outline"@click.stop="remove(node, data)">删除</el-button></span><div slot="reference" class="node-label"><div class="left" :title="node.label">{{ node.label }}</div></div></el-popover></el-tree><!-- 上传组件 --><sgUpload:disabledWhenShowSels="['.v-modal']":drag="uploadData ? dragUpload : false"ref="sgUpload":data="uploadData"@uploadSuccess="uploadSuccess"@uploadError="uploadError"@importError="importError"@showLoading="showLoading"@hideLoading="hideLoading"hideUploadTray/></div></div>
</template><script>
import sgUpload from "@/vue/components/admin/sgUpload";
export default {name: "sgTree",components: {sgUpload,},data() {return {// 动态树:增删改_________________________________________________________rootNode: null, //根节点rootResolve: null, //根节点focusNodeId: null, //聚焦高亮新添加IDmainKey: "id", //默认主键defaultRootId: "root", //默认根节点ID就是rootmaxAddLevel: null, // 最多允许添加的层级dragUpload: true, //在拖拽节点过程中控制上传组件能否拖拽上传// _________________________________________________________};},props: ["treeData","data","readonly","draggable", //是否开启拖拽节点功能"uploadData",/* 例子 uploadData: {accept: '.xls,.xlsx',actionUrl: `${this.$d.API_ROOT_URL}/core/resource/upload`,}, */"allowNodeDrag","allowNodeDrop","showCheckbox", //节点是否可被选择"hideRootNodeCheckbox", //隐藏一级节点复选框☑"disabledRootNode", //屏蔽一级节点勾选☑"defaultCheckedKeys", //默认勾选的节点的 key 的数组],watch: {data: {/* data.iconType= 节点图标:folder  文件夹normal  普通样式plus    加减符号样式*/handler(d) {d.nodeKey && (this.mainKey = d.nodeKey); //主键d.rootId && (this.defaultRootId = d.rootId); //根节点IDd.maxAddLevel && (this.maxAddLevel = d.maxAddLevel); // 最多允许添加的层级},deep: true,immediate: true,},},methods: {showLoading(file) {this.$emit(`showLoading`, file);},hideLoading(file) {this.$emit(`hideLoading`, file);},// 取消选中unCheckAll(d) {this.$refs.tree.setCheckedKeys([]);this.handleCheckChange([], []);},handleCheckChange(data, checked, indeterminate) {this.$emit(`checkChange`, {checkedNodes: this.$refs.tree.getCheckedNodes(),checkedLeafOnlyNodes: this.$refs.tree.getCheckedNodes(true, false), //(leafOnly, includeHalfChecked) 接收两个 boolean 类型的参数,1. 是否只是叶子节点,默认值为 false 2. 是否包含半选节点,默认值为 false【注意:懒加载树形不管用!必须要明确叶子节点展开后面没有子节点了才能识别!】data,checked,indeterminate,});},// 拖拽----------------------------------------nodeDragStart(node, ev) {this.dragUpload = false;this.$emit(`nodeDragStart`, node, ev);},nodeDragEnter(draggingNode, dropNode, ev) {this.$emit(`nodeDragEnter`, draggingNode, dropNode, ev);},nodeDragLeave(draggingNode, dropNode, ev) {this.$emit(`nodeDragLeave`, draggingNode, dropNode, ev);},nodeDragOver(draggingNode, dropNode, ev) {this.$emit(`nodeDragOver`, draggingNode, dropNode, ev);},nodeDragEnd(draggingNode, dropNode, dropType, ev) {// dropType有'before'、'after'、'inner'和'none'4种情况this.dragUpload = true;this.$emit(`nodeDragEnd`, draggingNode, dropNode, dropType, ev);},nodeDrop(draggingNode, dropNode, dropType, ev) {// dropType有'before'、'after'、'inner'和'none'4种情况this.$emit(`nodeDrop`, draggingNode, dropNode, dropType, ev);},allowDrop(draggingNode, dropNode, dropType) {// 拖拽时判定目标节点能否被放置。dropType 参数有三种情况:'prev'、'inner' 和 'next',分别表示放置在目标节点前、插入至目标节点和放置在目标节点后(注意:很奇葩上面node开头的绑定方法dropType有before、after、inner和none4种情况)return this.allowNodeDrop? this.allowNodeDrop(draggingNode, dropNode, dropType): true;},allowDrag(draggingNode) {return this.allowNodeDrag ? this.allowNodeDrag(draggingNode) : true;},// ----------------------------------------showAddButton(node) {if (this.maxAddLevel) {return node.level < this.maxAddLevel; // 最多允许添加的层级} else return true;},downloadTpl(d) {this.$emit(`downloadTpl`);},uploadSuccess(d, f) {this.$emit(`uploadSuccess`, d, f);},uploadError(d, f) {this.$emit(`uploadError`, d, f);},importError(d, f) {this.$emit(`importError`, d, f);},// 聚焦到某一个节点focusNode(id) {if (!id) return;this.$nextTick(() => {this.$refs.tree.setCurrentKey(id); //高亮显示某个节点this.$emit(`currentChange`, this.$refs.tree.getCurrentNode());this.$nextTick(() => {let dom = document.querySelector(`.el-tree-node.is-current`);dom &&dom.scrollIntoView({behavior: "smooth",block: "nearest",inline: "nearest",}); //缓慢滚动});});},// 添加根节点addRoot() {this.addNode(this.$refs.tree.root, { [this.mainKey]: this.defaultRootId });},// 通过id展开指定节点(通常是用于外部调用)expandNodeById(id) {let node = this.$refs.tree.getNode(id);node.expand();},//通过id勾选节点setCheckedKeys(ids) {this.$refs.tree.setCheckedKeys(ids);},// 添加节点addNode(node, data) {let resolve = (d) => {if (data.ID === this.defaultRootId) {this.treeData.unshift(d);} else {data.children || this.$set(data, "children", []);data.children.push(d);}node.expand();};let reject = (d) => {this.rootLoading = false;node.loading = false;this.$message.error(d.msg); //添加节点失败};this.$emit(`addNode`, { node, data, resolve, reject });},// 删除节点remove(node, data) {this.$confirm((this.data.text || {}).removeConfirmTip ||`此操作将永久删除该节点及其下面的节点,是否继续?`,(this.data.text || {}).removeConfirmTitle || `提示`,{dangerouslyUseHTMLString: true,confirmButtonText: `确定`,cancelButtonText: `取消`,type: "warning",}).then(() => {this.removeNodeData(node, data);}).catch(() => {});},// 删除节点数据(通过接口向后台删除数据)removeNodeData(node, data) {node.loading = true; //出现加载动画let resolve = (d) => {node.loading = false;this.$message.success(`删除成功`);// 从父节点异步删除子节点const parent = node.parent;const children = parent.data.children || parent.data;const index = children.findIndex((d) => d[this.mainKey] === data[this.mainKey]);children.splice(index, 1);// 从显示界面删除节点(有bug,只是删除了树节点的Virtual DOM,实际数据还在)/* let childNodes = node.parent.childNodes; childNodes.splice( childNodes.findIndex((d) => d.data[this.mainKey] === data[this.mainKey]), 1 ); */};let reject = (d) => {this.rootLoading = false;node.loading = false;this.$message.error(d.msg); //删除失败};this.$emit(`removeNode`, { node, data, resolve, reject });},// 当前选中节点变化时触发的事件current_change(d) {this.$emit(`currentChange`, d);},//点击节点nodeClick(d) {this.focusNodeId = null;this.$emit(`nodeClick`, d);},},
};
</script><style lang="scss" scoped>
@import "~@/css/sg";.sgTree {$treeHeaderHeight: 30px;width: 100%;height: 100%;display: flex;flex-wrap: nowrap;flex-direction: column;white-space: nowrap;flex-shrink: 0;flex-grow: 1;position: relative;.tree-header {display: flex;justify-content: space-between;align-items: center;height: $treeHeaderHeight;& > .sg-left {}& > .sg-right {}}.tree-container {position: relative;overflow: auto;box-sizing: border-box;height: calc(100% - #{$treeHeaderHeight});flex-shrink: 0;flex-grow: 1;user-select: none;@include scrollbarHover();/* >>> .tree-container .el-tree .el-tree-node__content {cursor: pointer;} */>>> .el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content {background-color: #409eff22; // 高亮当前选中节点背景}>>> .el-tree {* {transition: none;}.el-tree-node__children {min-width: max-content; //这样才会出现水平滚动条}.normal-tree-node,.plus-tree-node,.folder-tree-node {& + label:not(.el-checkbox) {/*单行省略号*/overflow: hidden;white-space: nowrap;text-overflow: ellipsis;}flex-shrink: 0;display: block;padding: 0 !important;margin: 0;width: 20px;height: 20px;margin-right: 5px;background: transparent url("~@/../static/img/fileType/folder/folder.svg")no-repeat center / contain;margin-left: 20px;& ~ span:not(.el-icon-loading) {width: 100%;.node-label {height: 40px;display: flex;align-items: center;}}&.expanded {flex-shrink: 0;transform: rotate(0deg);background-image: url("~@/../static/img/fileType/folder/folder-open.svg");}&.is-leaf {background-image: none;}}.normal-tree-node {margin-left: 10px;background-image: url("~@/../static/img/fileType/folder/arrow-right.svg");&.expanded {transform: rotate(90deg);background-image: url("~@/../static/img/fileType/folder/arrow-right.svg");}&.is-leaf {background-image: none;}}.plus-tree-node {margin-left: 10px;background-image: url("~@/../static/img/fileType/folder/plus.svg");&.expanded {background-image: url("~@/../static/img/fileType/folder/minus.svg");}&.is-leaf {background-image: none;}}// 隐藏一级节点的复选框&.hideRootNodeCheckbox > div > .el-tree-node__content .el-checkbox {display: none;}}}
}.tree-el-popover {.el-button {padding-top: 0;padding-bottom: 0;}
}
</style>

 应用

<template><div :class="$options.name"><sgTreev-loading="loading":key="$route.query.BMID + sgTree_fresh":treeData="treeData":data="treeConfigData"@currentChange="currentChange"@addNode="addNode"@removeNode="removeNode":uploadData="{name: `file`,accept: '.xls,.xlsx',actionUrl: `${$d.API_ROOT_URL}/core/column/importColumn`, //批量导入树结构接口actionData: {BMID: $global.getBMID(),PID: `root`,sgLog: `强哥请求来源:${$options.name}导入栏目xls`,},}"@uploadSuccess="uploadSuccess"@uploadError="uploadError"@importError="importError"@downloadTpl="downloadTpl"draggable:allowNodeDrop="allowNodeDrop"@nodeDragEnd="nodeDragEnd"/></div>
</template><script>
import sgTree from "@/vue/components/admin/sgTree";
export default {name: "sgBody",components: {sgTree,},data() {return {sgTree_fresh: false,autoId: 0, //自增编号treeConfigData: {nodeKey: `ID`, //主键props: { label: "MC", isLeaf: "leaf" }, //配置选项iconType: "plus", //节点图标:folder文件夹|normal普通样式|plus加减符号样式text: {addRootButtonText: "添加根目录", //添加根节点按钮文本removeConfirmTitle: "警告!!!", //删除节点提示标题removeConfirmTip: "此操作将永久删除该节点及其下面的子节点,是否继续?", //删除节点提示内容},},treeData: [],loading: false,};},created() {this.initTreeData();},methods: {//初始化数据initTreeData({ d } = {}) {this.$global.获取整棵树的数据({cb: (d) => {this.treeData = d;},});},// 拖拽节点相关方法----------------------------------------allowNodeDrop(draggingNode, dropNode, dropType) {// 只允许拖拽同级别前后排序let isPrevOrNext = dropType === "prev" || dropType === "next";// 同在第一级根节点下let isSameRootLevel =draggingNode.level === dropNode.level && draggingNode.level === 1;// 同在一个节点(非根节点)下let isSameChildLevel =draggingNode.parent &&dropNode.parent &&draggingNode.parent.data &&dropNode.parent.data &&draggingNode.parent.data.ID === dropNode.parent.data.ID;return isPrevOrNext && (isSameRootLevel || isSameChildLevel);},nodeDragEnd(draggingNode, dropNode, dropType, ev) {// 只允许拖拽同级别前后排序let isBeforeOrAfter = dropType === "before" || dropType === "after";if (isBeforeOrAfter) {/* console.log("被拖拽的节点", draggingNode.data.MC, draggingNode.data.PXZ); console.log("停靠的节点", dropNode.data.MC, dropNode.data.PXZ); */let theSameLevelDatas = (dropNode.parent.childNodes || []).map((v) => v.data); // 获取同一级节点数据theSameLevelDatas.forEach((v, i) => (v.PXZ = i)); //重新排序// console.log("拖拽排序", theSameLevelDatas); //这里需要调用后台接口let IDS = theSameLevelDatas.map((v) => v.ID); //排序后的ID顺序数组let data = {IDS,sgLog: `强哥请求来源:${this.$options.name}更改同一层级树节点排序值`,};this.$d.修改节点排序({data,r: {s: (d) => {// console.log("【成功】", d);},},});}},// ----------------------------------------// 获取当前聚焦节点的数据currentChange(d) {console.log(``, d);},// 添加节点addNode({ data, resolve }) {this.$d.新增节点({data: {MC: `新增节点名称(${++this.autoId})`,},doing: {l: { show: () => (this.loading = true), close: () => (this.loading = false) },s: (d) => resolve(d),f: (d) => reject(d), //删除失败},});},// 删除节点removeNode({ node, data, resolve, reject }) {this.$d.删除节点({data: { ID: data.ID },doing: {s: (d) => resolve(d),f: (d) => reject(d), //删除失败},});},updateList(d) {},uploadSuccess(d, f) {this.sgTree_fresh = !this.sgTree_fresh;},uploadError(d, f) {this.$message.error(d.msg);},// 导入失败importError(d, f) {},// 下载导入模板downloadTpl(d) {},},
};
</script>

关联懒加载树节点组件【sgLazyTree】自定义组件:动态懒加载el-tree树节点数据,实现增删改、懒加载及局部数据刷新。_el-tree 动态刷新-CSDN博客文章浏览阅读464次。【代码】【sgLazyTree】自定义组件:动态懒加载el-tree节点数据,实现增删改。_el-tree 动态刷新https://blog.csdn.net/qq_37860634/article/details/132639389

相关文章:

【sgTree】自定义组件:加载el-tree树节点整棵树数据,实现增删改操作。

特性 可以自定义主键、配置选项支持预定义节点图标&#xff1a;folder文件夹|normal普通样式多个提示文本可以自定义支持动态接口增删改节点可以自定义根节点id可以设置最多允许添加的层级深度支持拖拽排序&#xff0c;排序过程还可以针对拖拽的节点深度进行自定义限制支持隐藏…...

vue2面试题:vue组件之间的通信方式有哪些?

vue2面试题&#xff1a;vue组件之间的通信方式有哪些&#xff1f; 回答思路&#xff1a;1.组件通信的目的-->2.组件通信的分类-->3.组件通信的方案1.组件通信的目的2.组件通信的分类3.组件通信的方案&#xff08;1&#xff09;通过props传递数据&#xff08;2&#xff09…...

Pytorch神经网络模型nn.Sequential与nn.Linear

1、定义模型 对于标准深度学习模型&#xff0c;我们可以使用框架的预定义好的层。这使我们只需关注使用哪些层来构造模型&#xff0c;而不必关注层的实现细节。 我们首先定义一个模型变量net&#xff0c;它是一个Sequential类的实例。 Sequential类将多个层串联在一起。 当给…...

C++-gdb调试常用功能

文章目录 启动gdb运行程序设置断点运行控制查看源码查看信息查看变量线程相关 gdb调试常用功能如下&#xff0c;其中bin为要调试的程序&#xff0c;arg为参数 启动gdb 启动调试 gdb bin带参数启动 gdb --args bin arg1 arg2so预加载LD_PRELOAD/path/to/lib.so && gdb …...

快速上手的AI工具-文心一言辅助学习

前言 大家好晚上好&#xff0c;现在AI技术的发展&#xff0c;它已经渗透到我们生活的各个层面。对于普通人来说&#xff0c;理解并有效利用AI技术不仅能增强个人竞争力&#xff0c;还能在日常生活中带来便利。无论是提高工作效率&#xff0c;还是优化日常任务&#xff0c;AI工…...

Boost 适用 filesystem 库,statx 函数无法找到引用问题的解决方案。

1、boost 高版本使用了 statx 函数&#xff0c;这个函数是在 Linux 内核版本 4.11 之后引入的。 所以&#xff1a;可以升级 Linux 内核版本到4.11之后即可。 2、降低 boost 库版本到 1.70 以下 3、正确的路&#xff0c;改 boost 的编译代码 先看这个&#xff1a; Filesyste…...

MyBatis中一级缓存是什么?SqlSession一级缓存失效的原因?如何理解一级缓存?

一级缓存是SqlSession级别的&#xff0c;通过同一个SqlSession查询的数据会被缓存&#xff0c;下次查询相同的数据&#xff0c;就 会从缓存中直接获取&#xff0c;不会从数据库重新访问 使一级缓存失效的四种情况&#xff1a; 1) 不同的SqlSession对应不同的一级缓存 2) 同一…...

项目解决方案:多地医馆的高清视频监控接入汇聚联网

目 录 一、背景 二、建设目标及需求 1.建设目标 2.现状分析 3.需求分析 三、方案设计 1.设计依据 2.设计原则 3.方案设计 3.1 方案描述 3.2 组网说明 四、产品介绍 1.视频监控综合资源管理平台介绍 2.视频录像服务器和存储 2.1概述 2.2存储设计 …...

【前端基础--2】

选择器优先级 style标签中&#xff1a; .text{color: pink;}div{color: red;}#box{color: skyblue;} body标签中&#xff1a; <div class"text" id"box">猜猜我是什么颜色的</div> 运行结果&#xff1a; 选择器优先级权重&#xff1a; id选…...

【GitHub项目推荐--提取文字】【转载】

提取视频中的字幕 这个开源项目是提取视频中字幕的开源项目&#xff0c;提取视频中的关键帧&#xff0c;检测视频帧中文本的所在位置&#xff0c;识别视频帧中文本的内容。 不知道大家有没有做笔记的习惯&#xff0c;这个开源项目就很方便的把你一个视频中的字幕提取出来&…...

WebSocket与Shiro认证信息传递的实现与安全性探讨

在现代Web应用程序中&#xff0c;WebSocket已经成为实时双向通信的重要组件。而Shiro作为一个强大的Java安全框架&#xff0c;用于处理身份验证、授权和会话管理。本文将探讨如何通过WebSocket与Shiro集成&#xff0c;实现认证信息的传递&#xff0c;并关注在这一过程中确保安全…...

QT 实现自动生成小学两位数加减法算式

小学生加减法训练 QT实现–自动生成两位数加减法算式&#xff0c;并输出txt文件 可以copy到word文件&#xff0c;设置适当字体大小和行间距&#xff0c;带回家给娃做做题 void MainWindow::test(int answerMax, int count) {// 创建一个随机数生成器QRandomGenerator *gener…...

小程序学习-20

建议每次构建npm之前都先删除miniprogram_npm...

面试题-【消息队列】

消息队列 问题1 如何进行消息队列的技术选型优点解耦 &#xff08;pub/sub模型&#xff09;异步&#xff08;异步接口性能优化&#xff09;削峰 使用消息队列的缺点几种消息队列的特性 问题2 引入消息队列之后该如何保证其高可用性RabbitMQ的高可用kafka高可用 问题3 在消息队列…...

【江科大】STM32:I2C通信外设(硬件)

在将2C通信外设之前&#xff0c;我们先捋一捋&#xff0c;串口的相关特点来和I2C进行一个对北比。 首先&#xff1a; 1,大部分单片机&#xff0c;设计的PCB板均带有串口通信的引脚&#xff08;也就是通信基本都借助硬件收发器来实现&#xff09; 2.对于串口的异步时序&#xff…...

【机器学习300问】15、什么是逻辑回归模型?

一、逻辑回归模型是为了解决什么问题&#xff1f; 逻辑回归&#xff08;Logistic Regression&#xff09;是一种广义线性回归分析模型&#xff0c;尤其适用于解决二分类问题&#xff08;输出为两个类别&#xff09;。 &#xff08;1&#xff09;二分类举例 邮件过滤&#xff…...

C#调用C动态链接库

前言 已经没写过博客好久了&#xff0c;上一篇还是1年半前写的LTE Gold序列学习笔记&#xff0c;因为工作是做通信协议的&#xff0c;然后因为大学时没好好学习专业课&#xff0c;现在理论还不扎实&#xff0c;不敢瞎写&#xff1b; 因为工作原因&#xff0c;经常需要分析一些字…...

前端实现转盘抽奖 - 使用 lucky-canvas 插件

目录 需求背景需求实现实现过程图片示意实现代码 页面效果lucky-canvas 插件官方文档 需求背景 要求实现转盘转动抽奖的功能&#xff1a; 只有正确率大于等于 80% 才可以进行抽奖&#xff1b;“谢谢参与”概率为 90%&#xff0c;“恭喜中奖”概率为 10%&#xff1b; 需求实现 实…...

2024.1.23力扣每日一题——最长交替子数组

2024.1.23 题目来源我的题解方法一 枚举 题目来源 力扣每日一题&#xff1b;题序&#xff1a;2765 我的题解 方法一 枚举 每次都以两个相邻作为满足要求的循环数据&#xff0c;并且以一个布尔变量控制循环的位置 时间复杂度&#xff1a;O(n) 空间复杂度&#xff1a;O(1) pub…...

C语言王道练习题第七周两题

第一题 Description 输入一个学生的学号&#xff0c;姓名&#xff0c;性别&#xff0c;用结构体存储&#xff0c;通过 scanf 读取后&#xff0c;然后再 通过 printf 打印输出 Input 学号&#xff0c;姓名&#xff0c;性别&#xff0c;例如输入 101 xiongda m Output 输出…...

Vue3 的 JSX 函数组件,每次更新都会重新运行吗?

我用最直白、最无歧义、100%准确的方式&#xff0c;只回答你这一个问题&#xff1a; ✅ 最终答案&#xff08;背它&#xff09; 在 Vue3 中&#xff1a; 你写的 JSX 函数组件&#xff0c;整个函数 只会在组件初始化时运行 1 次&#xff01; 更新时&#xff0c;整个函数 不会重新…...

LeagueAkari:基于LCU API的英雄联盟自动化工具集架构设计与实战应用

LeagueAkari&#xff1a;基于LCU API的英雄联盟自动化工具集架构设计与实战应用 【免费下载链接】League-Toolkit 兴趣使然的、简单易用的英雄联盟工具集。支持战绩查询、自动秒选等功能。基于 LCU API。 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit L…...

uStepper S开源库深度解析:闭环步进控制与TMC2130驱动实战

1. uStepper S 开源驱动库深度解析&#xff1a;面向嵌入式工程师的实战指南 uStepper S 是一款集成了高性能步进电机驱动、高精度磁编码器反馈、ARM Cortex-M0 微控制器&#xff08;NXP LPC11U35&#xff09;与丰富外设接口的智能运动控制模块。其配套的 uStepper S Arduino…...

玩转AI!用FastAPI+RAG轻松构建智能文档问答系统,代码、文档全公开!

在企业数字化转型的浪潮中&#xff0c;我们常遇到这样一个痛点&#xff1a;海量的业务文档、研究报告、技术手册堆积如山&#xff0c;当需要从中寻找某个特定答案时&#xff0c;员工往往要花费数小时甚至数天进行翻阅。这不仅是效率的浪费&#xff0c;更是知识资产沉睡的体现**…...

嵌入式OLED UI组件库:轻量级C++组件化设计

1. 项目概述 OLED UI Components 是一个面向嵌入式平台的轻量级、组件化 OLED 用户界面开发库&#xff0c;专为基于 SSD1306 驱动芯片的单色 OLED 显示屏&#xff08;典型分辨率为 12864&#xff09;设计。该库不直接操作硬件寄存器&#xff0c;而是构建在 Adafruit_SSD1306 库…...

无损视频剪辑神器LosslessCut:3分钟学会零编码损耗的专业剪辑技巧

无损视频剪辑神器LosslessCut&#xff1a;3分钟学会零编码损耗的专业剪辑技巧 【免费下载链接】lossless-cut The swiss army knife of lossless video/audio editing 项目地址: https://gitcode.com/gh_mirrors/lo/lossless-cut 你是否还在为视频剪辑时画质损失而烦恼&…...

GPStar Audio串口控制库:嵌入式多轨音频系统开发指南

1. GPStar Audio Serial Library 技术深度解析GPStar Audio Serial Library 是专为 GPStar Technologies 公司推出的 GPStar Audio 与 GPStar Audio XL 系列嵌入式音频播放器设计的串行通信控制库。该库并非通用音频驱动&#xff0c;而是针对特定硬件平台深度定制的、面向实时交…...

OpenClaw技能市场盘点:10个适配Qwen3.5-4B-Claude的实用工具

OpenClaw技能市场盘点&#xff1a;10个适配Qwen3.5-4B-Claude的实用工具 1. 为什么需要关注技能适配性 当我第一次在OpenClaw上尝试安装第三方技能时&#xff0c;遇到了一个典型问题&#xff1a;技能安装成功了&#xff0c;但执行时模型总是输出"我不明白这个请求"…...

2024版idea引入lombok总是报错解决方法

在创建SpringBoot文件时不勾选lombok&#xff0c;然后自己手动导入lombok并指定版本玛德这idea的SpringBoot中导入lombok后我使用Data总是说我的get和set方法有毛病&#xff0c;一怒之下我直接就是疯狂搜如何解决lombok引用问题&#xff0c;结果不是让我去勾选一个东西就是让我…...

Windows 10 实战:基于 FFmpeg + Nginx 构建 RTSP 转 RTMP/HLS 流媒体网关

1. 为什么需要RTSP转RTMP/HLS网关 最近接手了一个监控项目&#xff0c;甲方要求将内网摄像头的实时画面通过网页展示给外网用户。刚开始觉得挺简单&#xff0c;直到发现摄像头输出的是RTSP协议——这玩意儿在浏览器里根本没法直接播放&#xff01;相信不少做过视频监控开发的同…...