Vue3 + Element-plus + TS —— 动态表格自由编辑
前期回顾
《 穿越时空的代码、在回首:Evil.js两年后的全新解读 》-CSDN博客
Vue3 + TS + Element-Plus 封装Tree组件 《亲测可用》_
https://blog.csdn.net/m0_57904695/article/details/131664157?spm=1001.2014.3001.5501
态表格 自由编辑
目录
♻️ 效果图
🚩 Vue2 版本
🐗 Vue3 版本
♻️ 效果图

👉 在线预览
🚩 Vue2 版本
<template><!-- 可编辑表格V2 --><div id="hello"><!-- 表格 --><p class="tips">单击 右键菜单,单击 左键编辑</p><el-table:data="tableData"height="500px"borderstyle="width: 100%; margin-top: 10px"@cell-click="cellDblclick"@header-contextmenu="(column, event) => rightClick(null, column, event)"@row-contextmenu="rightClick":row-class-name="tableRowClassName"><el-table-columnv-if="columnList.length > 0"type="index":label="'No.'"/><el-table-columnv-for="(col, idx) in columnList":key="col.prop":prop="col.prop":label="col.label":index="idx"/></el-table><div><h3 style="text-align: center">实时数据展示</h3><label>当前目标:</label><p>{{ JSON.stringify(curTarget) }}</p><label>表头:</label><p v-for="col in columnList" :key="col.prop">{{ JSON.stringify(col) }}</p><label>数据:</label><p v-for="(data, idx) in tableData" :key="idx">{{ JSON.stringify(data) }}</p></div><!-- 右键菜单框 --><div v-show="showMenu" id="contextmenu" @mouseleave="showMenu = false"><p style="margin-bottom: 10px">列:</p><el-button size="mini" type="primary" @click="addColumn()">前方插入一列</el-button><el-button size="mini" type="primary" @click="addColumn(true)">后方插入一列</el-button><el-buttontype="primary"size="mini"@click="openColumnOrRowSpringFrame('列')">删除当前列</el-button><el-button size="mini" type="primary" @click="renameCol($event)">更改列名</el-button><div class="line"></div><p style="margin-bottom: 12px">行:</p><el-buttonsize="mini"type="primary"@click="addRow()"v-show="!curTarget.isHead">上方插入一行</el-button><el-buttonsize="mini"type="primary"@click="addRow(true)"v-show="!curTarget.isHead">下方插入一行</el-button><el-buttonsize="mini"type="primary"@click="addRowHead(true)"v-show="curTarget.isHead">下方插入一行</el-button><el-buttontype="primary"size="mini"@click="openColumnOrRowSpringFrame('行')"v-show="!curTarget.isHead">删除当前行</el-button></div><!-- 单元格/表头内容编辑框 --><div v-show="showEditInput" id="editInput"><el-inputv-focusplaceholder="请输入内容"v-model="curTarget.val"clearable@change="updTbCellOrHeader"@blur="showEditInput = false"@keyup="onKeyUp($event)"><template #prepend>{{ curColumn.label || curColumn.prop }}</template></el-input></div></div>
</template><script>
export default {data() {return {columnList: [{ prop: "name", label: "姓名" },{ prop: "age", label: "年龄" },{ prop: "city", label: "城市" },{ prop: "tel", label: "电话" }],tableData: [{ name: "张三", age: 24, city: "广州", tel: "13312345678" },{ name: "李四", age: 25, city: "九江", tel: "18899998888" }],showMenu: false, // 显示右键菜单showEditInput: false, // 显示单元格/表头内容编辑输入框curTarget: {// 当前目标信息rowIdx: null, // 行下标colIdx: null, // 列下标val: null, // 单元格内容/列名isHead: undefined // 当前目标是表头?},countCol: 0 // 新建列计数};},computed: {curColumn() {return this.columnList[this.curTarget.colIdx] || {};}},methods: {// 删除当前列或当前行openColumnOrRowSpringFrame(type) {this.$confirm(`此操作将永久删除该 ${type === "列" ? "列" : "行"}, 是否继续 ?, '提示'`,{confirmButtonText: "确定",cancelButtonText: "取消",type: "warning"}).then(() => {if (type === "列") {this.delColumn();} else if (type === "行") {this.delRow();}this.$message({type: "success",message: "删除成功!"});}).catch(() => {this.$message({type: "info",message: "已取消删除"});});},// 回车键关闭编辑框onKeyUp(e) {if (e.keyCode === 13) {this.showEditInput = false;}},// 单元格双击事件 - 更改单元格数值cellDblclick(row, column, cell, event) {this.showEditInput = false;if (column.index == null) return;this.locateMenuOrEditInput("editInput", 200, event); // 编辑框定位this.showEditInput = true;// 当前目标this.curTarget = {rowIdx: row.row_index,colIdx: column.index,val: row[column.property],isHead: false};},// 单元格/表头右击事件 - 打开菜单rightClick(row, column, event) {// 阻止浏览器自带的右键菜单弹出event.preventDefault(); // window.event.returnValue = falsethis.showMenu = false;if (column.index == null) return;this.locateMenuOrEditInput("contextmenu", 140, event); // 菜单定位this.showMenu = true;// 当前目标this.curTarget = {rowIdx: row ? row.row_index : null, // 目标行下标,表头无 row_indexcolIdx: column.index, // 目标项下标val: row ? row[column.property] : column.label, // 目标值,表头记录名称isHead: !row};},// 去更改列名renameCol($event) {this.showEditInput = false;if (this.curTarget.colIdx === null) return;this.locateMenuOrEditInput("editInput", 200, $event); // 编辑框定位this.showEditInput = true;},// 更改单元格内容/列名updTbCellOrHeader(val) {if (!this.curTarget.isHead)// 更改单元格内容this.tableData[this.curTarget.rowIdx][this.curColumn.prop] = val;else {// 更改列名if (!val) return;this.columnList[this.curTarget.colIdx].label = val;}},// 新增行addRow(later) {this.showMenu = false;const idx = later ? this.curTarget.rowIdx + 1 : this.curTarget.rowIdx;let obj = {};this.columnList.forEach((p) => (obj[p.prop] = ""));this.tableData.splice(idx, 0, obj);},// 表头下新增行addRowHead() {// 关闭菜单this.showMenu = false;// 新增行let obj = {};// 初始化行数据this.columnList.forEach((p) => (obj[p.prop] = ""));// 插入行数据this.tableData.unshift(obj);},// 删除行delRow() {this.showMenu = false;this.curTarget.rowIdx !== null &&this.tableData.splice(this.curTarget.rowIdx, 1);},// 新增列addColumn(later) {this.showMenu = false;const idx = later ? this.curTarget.colIdx + 1 : this.curTarget.colIdx;const colStr = { prop: "col_" + ++this.countCol, label: "" };this.columnList.splice(idx, 0, colStr);this.tableData.forEach((p) => (p[colStr.prop] = ""));},// 删除列delColumn() {this.showMenu = false;this.tableData.forEach((p) => {delete p[this.curColumn.prop];});this.columnList.splice(this.curTarget.colIdx, 1);},// 添加表格行下标tableRowClassName({ row, rowIndex }) {row.row_index = rowIndex;},// 定位菜单/编辑框locateMenuOrEditInput(eleId, eleWidth, event) {let ele = document.getElementById(eleId);ele.style.top = event.clientY - 100 + "px";ele.style.left = event.clientX - 50 + "px";if (window.innerWidth - eleWidth < event.clientX) {ele.style.left = "unset";ele.style.right = 0;}}}
};
</script><style lang="scss" scoped>
#hello {position: relative;height: 100%;width: 100%;
}
.tips {margin-top: 10px;color: #999;
}
#contextmenu {position: absolute;top: 0;left: 0;height: auto;width: 120px;border-radius: 3px;box-shadow: 0 0 10px 10px #e4e7ed;background-color: #fff;border-radius: 6px;padding: 15px 0 10px 15px;button {display: block;margin: 0 0 5px;}
}
.hideContextMenu {position: absolute;top: -4px;right: -5px;
}
#editInput,
#headereditInput {position: absolute;top: 0;left: 0;height: auto;min-width: 200px;max-width: 400px;padding: 0;
}
#editInput .el-input,
#headereditInput .el-input {outline: 0;border: 1px solid #c0f2f9;border-radius: 5px;box-shadow: 0px 0px 10px 0px #c0f2f9;
}
.line {width: 100%;border: 1px solid #e4e7ed;margin: 10px 0;
}
</style>
🐗 Vue3 版本
<template><div id="table-wrap"><!-- 可编辑表格-Vue3 + ElementPlus --><el-table:data="questionChoiceVOlist"stripeborder@cell-click="cellClick"@row-contextmenu="rightClick":row-class-name="tableRowClassName"@header-contextmenu="(column: any, event: MouseEvent) => rightClick(null, column, event)"><el-table-columntype="index"label="序号"align="center":resizable="false"width="70"/><template #empty><el-empty description="暂无数据" /></template><el-table-column:resizable="false"align="center"v-for="(col, idx) in columnList":key="col.prop":prop="col.prop":label="col.label":index="idx"><template #default="{ row }"><divv-if="col.type === 'button'"style="height: 75px; padding-top: 26px; width: 100%"><el-badge type="warning" :value="getRiskLenght(row.riskIds)"><el-button size="small">{{ paramsIdType == 'detail' ? '查看' : '选择' }}</el-button></el-badge></div><el-input-numberv-if="col.type === 'input-number'"v-model.number="row[col.prop]":min="0":max="10":step="0.1":precision="2"/></template></el-table-column></el-table><!-- 右键菜单框 --><div v-show="showMenu" id="contextmenu" @mouseleave="showMenu = false"><p style="margin-bottom: 10px; text-align: left">列:</p><el-button :icon="CaretTop" @click="addColumn(false)"> 前方插入一列 </el-button><el-button :icon="CaretBottom" @click="addColumn(true)"> 后方插入一列 </el-button><el-button :icon="DeleteFilled" @click="openColumnOrRowSpringFrame('列')">删除当前列</el-button><el-button @click="renameCol" :icon="EditPen"> 更改列名 </el-button><div style="color: #ccc">-----------------------</div><p style="margin-bottom: 12px">行:</p><el-button :icon="CaretTop" @click="addRow(false)" v-show="!curTarget.isHead">上方插入一行</el-button><el-button :icon="CaretBottom" @click="addRow(true)" v-show="!curTarget.isHead">下方插入一行</el-button><el-button :icon="DeleteFilled" @click="addRowHead" v-show="curTarget.isHead">下方插入一行</el-button><el-button:icon="DeleteFilled"@click="openColumnOrRowSpringFrame('行')"v-show="!curTarget.isHead">删除当前行</el-button></div><!-- 输入框 --><div v-show="showEditInput" id="editInput"><el-inputref="iptRef"placeholder="请输入内容"v-model="curTarget.val"clearable@change="updTbCellOrHeader"@blur="showEditInput = false"@keyup="onKeyUp($event)"><template #prepend>{{ curColumn.label || curColumn.prop }}</template></el-input></div><!-- 实时数据展示 Start--><!-- 第二个和第三个参数来格式化JSON输出,其中null作为替换函数(这里不进行替换),2表示缩进级别。这样JSON数据会以格式化的形式展示,增加了可读性--><div><h3 style="text-align: center; margin-top: 15px">实时数据展示</h3><label>当前目标:</label><pre><code>{{ JSON.stringify(curTarget, null, 2) }}</code></pre><div style="width: 100%; height: auto"><label>表头:</label><pre><code v-for="col in columnList" :key="col.prop">{{ JSON.stringify(col, null, 2) }}</code></pre></div><div><label>数据:</label><pre><code v-for="(data, idx) in questionChoiceVOlist" :key="idx">{{ JSON.stringify(data, null, 2) }}</code></pre></div></div><!-- 实时数据展示 End--></div>
</template><script setup lang="ts">
import { ref, reactive, computed, toRefs, nextTick } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { DeleteFilled, CaretBottom, CaretTop, EditPen } from '@element-plus/icons-vue';
// Tips: locateMenuOrEditInput 可调整编辑框位置
interface Column {prop: string;label: string;type?: string;
}interface Data {choiceCode: string;choiceContent: string;riskIds: string;itemScore: string | number;[key: string]: unknown;
}interface Target {rowIdx: number | null;colIdx: number | null;val: string | null;isHead: boolean | undefined;
}// 接收addEdit父组件传过来的数据,用于判断是新增、编辑、详情页面
const paramsIdType = 'detail';const state = reactive({columnList: [{ prop: 'choiceCode', label: '选项编码' },{ prop: 'choiceContent', label: '选项内容' },{ prop: 'riskIds', label: '风险点', type: 'button' },{ prop: 'itemScore', label: '选项分值', type: 'input-number' },] as Column[],questionChoiceVOlist: [{choiceCode: 'A',choiceContent: '是',riskIds: '45,47',itemScore: 1,isClickCheckBtn: true,id: 1,},{choiceCode: 'B',choiceContent: '否',riskIds: '46',itemScore: 4,isClickCheckBtn: true,id: 2,},{choiceCode: 'C',choiceContent: '否',riskIds: '',itemScore: 4,isClickCheckBtn: true,id: 3,},] as Data[],showMenu: false, // 显示右键菜单showEditInput: false, // 显示单元格/表头内容编辑输入框curTarget: {// 当前目标信息rowIdx: null, // 行下标colIdx: null, // 列下标val: null, // 单元格内容/列名isHead: undefined, // 当前目标是表头?} as Target,countCol: 0, // 新建列计数
});
const iptRef = ref();const { columnList, questionChoiceVOlist, showMenu, showEditInput, curTarget } = toRefs(state);// 当前列
const curColumn = computed(() => {return curTarget.value.colIdx !== null? columnList.value[curTarget.value.colIdx]: { prop: '', label: '' };
});// 计算风险点数量
const getRiskLenght = computed(() => {return (riskIds: string) => riskIds.split(',').filter(Boolean).length;
});/*** 删除列/行* @method delColumn* @param { string } type - '列' | '行'**/
const openColumnOrRowSpringFrame = (type: string) => {ElMessageBox.confirm(`此操作将永久删除该${type === '列' ? '列' : '行'}, 是否继续 ?, '提示'`, {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning',}).then(() => {if (type === '列') {delColumn();} else if (type === '行') delRow();ElMessage.success('删除成功');}).catch(() => ElMessage.info('已取消删除'));
};// 回车键关闭编辑框
const onKeyUp = (e: KeyboardEvent) => {if (e.key === 'Enter') {showEditInput.value = false;}
};// 控制某字段不能打开弹框
const isPop = (column: { label: string }) => {return column.label === '风险点' || column.label === '选项分值';
};// 左键输入框
const cellClick = (row: { [x: string]: any; row_index: any },column: { index: null; property: string | number; label: string },_cell: any,event: MouseEvent
) => {// 如果是风险点或选项分值,不执行后续代码if (isPop(column)) return;iptRef.value.focus();if (column.index == null) return;locateMenuOrEditInput('editInput', -300, event); // 左键输入框定位 YshowEditInput.value = true;iptRef.value.focus();// 当前目标curTarget.value = {rowIdx: row.row_index,colIdx: column.index,val: row[column.property],isHead: false,};
};// 表头右击事件 - 打开菜单
const rightClick = (row: any, column: any, event: MouseEvent) => {event.preventDefault();if (column.index == null) return;// 如果tableData有数据并且当前目标是表头,那么就返回,不执行后续操作// if (questionChoiceVOlist.value.length > 0 && !row) return;if (isPop(column)) return;showMenu.value = false;locateMenuOrEditInput('contextmenu', -500, event); // 右键输入框showMenu.value = true;curTarget.value = {rowIdx: row ? row.row_index : null,colIdx: column.index,val: row ? row[column.property] : column.label,isHead: !row,};
};// 更改列名
const renameCol = () => {showEditInput.value = false;if (curTarget.value.colIdx === null) return;showEditInput.value = true;nextTick(() => {iptRef.value.focus();});
};// 更改单元格内容/列名
const updTbCellOrHeader = (val: string) => {if (!curTarget.value.isHead) {if (curTarget.value.rowIdx !== null) {(questionChoiceVOlist.value[curTarget.value.rowIdx] as Data)[curColumn.value.prop] =val;}} else {if (!val) return;if (curTarget.value.colIdx !== null) {columnList.value[curTarget.value.colIdx].label = val;}}
};
// 新增行
const addRow = (later: boolean) => {showMenu.value = false;const idx = later ? curTarget.value.rowIdx! + 1 : curTarget.value.rowIdx!;let obj: any = {};columnList.value.forEach((p) => obj[p.prop]);questionChoiceVOlist.value.splice(idx, 0, obj);// 设置新增行数据默认值questionChoiceVOlist.value[idx] = {choiceCode: '',choiceContent: '',riskIds: '',itemScore: 0,id: Math.floor(Math.random() * 100000),};
};// 表头下新增行
const addRowHead = () => {showMenu.value = false;let obj: any = {};columnList.value.forEach((p) => obj[p.prop]);questionChoiceVOlist.value.unshift(obj);questionChoiceVOlist.value[0] = {choiceCode: '',choiceContent: '',riskIds: '',itemScore: 0,id: Math.floor(Math.random() * 100000),};
};
// 删除行
const delRow = () => {showMenu.value = false;curTarget.value.rowIdx !== null &&questionChoiceVOlist.value.splice(curTarget.value.rowIdx!, 1);
};// 新增列
const addColumn = (later: boolean) => {showMenu.value = false;const idx = later ? curTarget.value.colIdx! + 1 : curTarget.value.colIdx!;const colStr = { prop: 'Zk-NewCol - ' + ++state.countCol, label: '' };columnList.value.splice(idx, 0, colStr);questionChoiceVOlist.value.forEach((p) => (p[colStr.prop] = ''));
};// 删除列
const delColumn = () => {showMenu.value = false;questionChoiceVOlist.value.forEach((p) => {delete p[curColumn.value.prop];});columnList.value.splice(curTarget.value.colIdx!, 1);
};// 添加表格行下标
const tableRowClassName = ({ row, rowIndex }: { row: any; rowIndex: number }) => {row.row_index = rowIndex;
};// 定位菜单/编辑框
const locateMenuOrEditInput = (eleId: string, distance: number, event: MouseEvent) => {if (window.innerWidth < 1130 || window.innerWidth < 660)return ElMessage.warning('窗口太小,已经固定菜单位置,或请重新调整窗口大小');const ele = document.getElementById(eleId) as HTMLElement;const x = event.pageX;const y = event.clientY + 200; //右键菜单位置 Ylet left = x + distance + 200; //右键菜单位置 Xlet top;if (eleId == 'editInput') {// 左键top = y + distance;left = x + distance - 120;} else {// 右键top = y + distance + 170;}ele.style.left = `${left}px`;ele.style.top = `${top}px`;
};defineExpose({questionChoiceVOlist,
});
</script><style lang="scss" scoped>
#table-wrap {width: 100%;height: 100%;/* 左键 */#contextmenu {position: absolute;display: flex;flex-direction: column;align-items: center;justify-content: center;z-index: 999999;top: 0;left: 0;height: auto;width: 200px;border-radius: 3px;border: #e2e2e2 1px solid;box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);background-color: #fff;border-radius: 6px;padding: 15px 10px 14px 12px;button {display: block;margin: 0 0 5px;}}/* 右键 */#editInput {position: absolute;top: 0;left: 0;z-index: 999999;}/* 实时数据 */pre {border: 1px solid #cccccc;padding: 10px;overflow: auto;}
}
</style>

_______________________________ 期待再见 _______________________________
相关文章:
Vue3 + Element-plus + TS —— 动态表格自由编辑
前期回顾 《 穿越时空的代码、在回首:Evil.js两年后的全新解读 》-CSDN博客 Vue3 TS Element-Plus 封装Tree组件 《亲测可用》_ https://blog.csdn.net/m0_57904695/article/details/131664157?spm1001.2014.3001.5501 态表格 自由编辑 目录 ♻️ 效果图…...
虚拟机配置桥接模式
背景 因为要打一些awd比赛,一些扫描工具什么的,要用到kali,就想着换成一个桥接模式 但是我看网上的一些文章任然没弄好,遇到了一些问题 前置小问题 每次点开虚拟网络编辑器的时候都没有vmnet0,但是点击更改的时候却有vmnet0 第一步: 点击更改设置 第二步: 把wmnet0删掉 …...
星戈瑞DSPE-SS-PEG-CY7近红外花菁染料
DSPE-SS-PEG-CY7是一种具有复杂而精细结构的复合纳米材料,其在生物医学领域的应用增多。该材料结合了磷脂(DSPE)、聚乙二醇(PEG)、二硫键(SS)以及荧光染料(CY7)的特点&am…...
LeetCode:503. 下一个更大元素 II(Java 单调栈)
目录 503. 下一个更大元素 II 题目描述: 实现代码与解析: 单调栈 原理思路: 503. 下一个更大元素 II 题目描述: 给定一个循环数组 nums ( nums[nums.length - 1] 的下一个元素是 nums[0] )&…...
代码重构:解读重构概念及重构实战
目录 一.重构是什么(what) 1.重构的本质 2.重构≠性能优化 二.重构的目的(why) 1.去写好的代码 2.去写更灵活的代码 三.重构的时机(when and where) 1.何时重构 2.何时不重构 四.重构的方法(how) 1.重构关键核心 2.重构方法 3.重构工具 小结 一.重构是什么(what)…...
java.util.Optional类介绍
java.util.Optional 是 Java 8 引入的一个容器类,用于表示可能包含或不包含非空值的对象。它的设计初衷是为了减少程序中的空指针异常(NullPointerException),并使代码更加简洁和易读。 Optional 类的介绍 1. 特点 避免显式的 null 检查:使用 Optional 可以避免显式的 n…...
PhotoShop自动生成号码牌文件
1、说明 设计卡牌的时候,遇到自动生成编号,从01500到-02500,一个一个的手写,在存储保存成psd格式的文件,会很耗时。 下面将介绍如何使用ps自动生成psd格式的文件 2、使用excle生成数字 从01500到-02500 第一步&…...
02逻辑代数与硬件描述语言基础
2.1 逻辑代数(简单逻辑的运算) 2.2 逻辑函数的卡诺图(从图论的角度)化简法 2.3 硬件描述语言Verilog HDL基础(研究生阶段才用得到) 要求: 1、熟悉逻辑代数常用基本定律、恒等式和规则。 2、掌握…...
OpenGL3.3_C++_Windows(21)
抗锯齿 遇到模型边缘有锯齿:光栅器将顶点数据转化为片段的方式有关 抗锯齿:产生更平滑的边缘SSAA超采样抗锯齿:使用比正常分辨率更高的分辨率,来渲染场景,它也会带来很大的性能开销。 光栅器: 位于最终处…...
clickhouse学习
ClickHouse学习 安装部署 1.下载rpm文件 下载地址:https://packages.clickhouse.com/rpm/stable/ clickhouse-client-23.2.1.2537.x86_64.rpm clickhouse-common-static-23.2.1.2537.x86_64.rpm clickhouse-common-static-dbg-23.2.1.2537.x86_64.rpm clickhous…...
MySQL高级-索引-使用规则-前缀索引
文章目录 1、前缀索引2、前缀长度3、查询表数据4、查询表的记录总数5、计算并返回具有电子邮件地址(email)的用户的数量6、从tb_user表中计算并返回具有不同电子邮件地址的用户的数量7、计算唯一电子邮件地址(email)的比例相对于表…...
外星生命在地球的潜在存在:科学、哲学与社会的交织
外星生命在地球的潜在存在:科学、哲学与社会的交织 摘要:近年来,关于外星生命是否存在的讨论日益激烈。有研究表明,外星人可能已经在地球漫步,这一观点引发了广泛的科学、哲学和社会学思考。本文将从科学角度探讨外星…...
使用FRP 0.58版本进行内网穿透的详细教程
什么是FRP? FRP(Fast Reverse Proxy)是一款高性能的反向代理应用,主要用于内网穿透。通过FRP,您可以将内网服务暴露给外网用户,无需进行复杂的网络配置。 准备工作 服务器:一台具备公网IP的服…...
0000电子技术基础概述
数电 未来课的基础 以前是模块、器件级 现在是 系统级 价格、性能、 技术更新快速的好处:得到了实惠 坏处:工程师需要不断地学习,不变就容易out,要用发展的眼光看待问题 了解基础知识、还要有前沿概念。 理论课、实践课要相结…...
vscode+platformio使用STC官方库进行51单片机开发 -- 中断异常
问题描述 在进行STC8H1K08单片机的开发时,使用官方提供的C语言库函数,在vscodeplatformio开发环境下发现库函数的串口中断异常,看起来像是中断没有触发。 解决过程 用串口中断时一直没有触发中断,起初没有怀疑是中断的问题&…...
探索Android架构设计
Android 应用架构设计探索:MVC、MVP、MVVM和组件化 MVC、MVP和MVVM是常见的三种架构设计模式,当前MVP和MVVM的使用相对比较广泛,当然MVC也并没有过时之说。而所谓的组件化就是指将应用根据业务需求划分成各个模块来进行开发,每个…...
基于matlab的不同边缘检测算子的边缘检测
1 原理 1.1 边缘检测概述 边缘检测是图像处理和计算机视觉中的基本问题,其目的在于标识数字图像中亮度变化明显的点。这些变化通常反映了图像属性的重要事件和变化,如深度不连续、表面方向不连续、物质属性变化和场景照明变化等。边缘检测在特征提取中…...
CentOS安装ntp时间同步服务
CentOS安装ntp时间同步服务 安装ntp 检查服务器是否安装ntp: rpm -q ntp安装ntp: yum install -y ntp服务端配置 配置文件路径:/etc/ntp.conf 设置ntp为开机启动 systemctl enable ntpd查看ntp开机启动状态 enabled:开启, disabled:关闭 …...
【Linux进阶】UNIX体系结构分解——操作系统,内核,shell
1.什么是操作系统? 从严格意义上说,可将操作系统定义为一种软件,它控制计算机硬件资源,提供程序运行环境。我们通常将这种软件称为内核(kerel),因为它相对较小,而且位于环境的核心。 从广义上…...
PageOffice国产版在线编辑word文件
PageOffice国产版支持统信UOS、银河麒麟等国产操作系统。调用客户端WPS在线编辑word、excel、ppt等文件。在线编辑效果与本地WPS一致。如图所示: web系统集成pageofficeV6.0国产版的文档:PageOfficeV6.0国产版最简集成代码(Springboot) PageOffice最简集…...
springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...
如何在看板中有效管理突发紧急任务
在看板中有效管理突发紧急任务需要:设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP(Work-in-Progress)弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中,设立专门的紧急任务通道尤为重要,这能…...
论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
springboot 日志类切面,接口成功记录日志,失败不记录
springboot 日志类切面,接口成功记录日志,失败不记录 自定义一个注解方法 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;/***…...
Docker拉取MySQL后数据库连接失败的解决方案
在使用Docker部署MySQL时,拉取并启动容器后,有时可能会遇到数据库连接失败的问题。这种问题可能由多种原因导致,包括配置错误、网络设置问题、权限问题等。本文将分析可能的原因,并提供解决方案。 一、确认MySQL容器的运行状态 …...
论文阅读:Matting by Generation
今天介绍一篇关于 matting 抠图的文章,抠图也算是计算机视觉里面非常经典的一个任务了。从早期的经典算法到如今的深度学习算法,已经有很多的工作和这个任务相关。这两年 diffusion 模型很火,大家又开始用 diffusion 模型做各种 CV 任务了&am…...
ui框架-文件列表展示
ui框架-文件列表展示 介绍 UI框架的文件列表展示组件,可以展示文件夹,支持列表展示和图标展示模式。组件提供了丰富的功能和可配置选项,适用于文件管理、文件上传等场景。 功能特性 支持列表模式和网格模式的切换展示支持文件和文件夹的层…...
