Vue3 + Element-plus + TS —— 动态表格自由编辑

news2024/12/27 22:31:24

9a69fede8b2044a79dd834e3e48f20b4.png前期回顾   

《 穿越时空的代码、在回首:Evil.js两年后的全新解读 》-CSDN博客

Vue3 + TS + Element-Plus 封装Tree组件 《亲测可用》_ icon-default.png?t=N7T8https://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"
      border
      style="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-column
        v-if="columnList.length > 0"
        type="index"
        :label="'No.'"
      />
      <el-table-column
        v-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-button
        type="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-button
        size="mini"
        type="primary"
        @click="addRow()"
        v-show="!curTarget.isHead"
      >
        上方插入一行
      </el-button>
      <el-button
        size="mini"
        type="primary"
        @click="addRow(true)"
        v-show="!curTarget.isHead"
      >
        下方插入一行
      </el-button>
      <el-button
        size="mini"
        type="primary"
        @click="addRowHead(true)"
        v-show="curTarget.isHead"
      >
        下方插入一行
      </el-button>
      <el-button
        type="primary"
        size="mini"
        @click="openColumnOrRowSpringFrame('行')"
        v-show="!curTarget.isHead"
      >
        删除当前行
      </el-button>
    </div>
 
    <!-- 单元格/表头内容编辑框 -->
    <div v-show="showEditInput" id="editInput">
      <el-input
        v-focus
        placeholder="请输入内容"
        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 = false
      this.showMenu = false;
      if (column.index == null) return;
      this.locateMenuOrEditInput("contextmenu", 140, event); // 菜单定位
      this.showMenu = true;
      // 当前目标
      this.curTarget = {
        rowIdx: row ? row.row_index : null, // 目标行下标,表头无 row_index
        colIdx: 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"
			stripe
			border
			@cell-click="cellClick"
			@row-contextmenu="rightClick"
			:row-class-name="tableRowClassName"
			@header-contextmenu="(column: any, event: MouseEvent) => rightClick(null, column, event)"
		>
			<el-table-column
				type="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 }">
					<div
						v-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-number
						v-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-input
				ref="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); // 左键输入框定位 Y
	showEditInput.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; //右键菜单位置 Y
	let left = x + distance + 200; //右键菜单位置 X
	let 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>

7730e2bd39d64179909767e1967da702.jpeg

 _______________________________  期待再见  _______________________________

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

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

相关文章

【物联网】物联网操作系统简介

目录 一、物联网操作系统概述 1.1内存占用 1.2 内存管理 二、物联网操作系统构成 三、物联网操作系统关键特性 3.1 调度方式 3.2 I/O操作方式 3.3 网络服务 3.3.1 TinyOS网络协议栈 3.3.2 LiteOS网络协议栈 一、物联网操作系统概述 物联网操作系统是支撑物联网大规模…

极限编程里最容易被忽略的实践

在前面的一篇文章里面我和大家聊过了极限编程的重要性&#xff0c;今天想和大家聊聊极限编程里面最简单但也往往最容易被忽略的实践——编码规范。 说到编码规范&#xff0c;每一个开发人员都非常熟悉&#xff0c;每一个团队也都有自己的编码规范。但实际的执行情况如何呢&…

MySQL 8版本的新功能和改进有哪些?(MySQL收藏版)

目录 1. 简单介绍 2. 发展历史 3. MySQL 8产品特性 4. 数据库性能重点分析 1. 原生 JSON 支持改进 2. 隐式列优化 3. 改进的查询优化器 4. 并行查询 5. 分区表改进 MySQL 是一个流行的开源关系型数据库管理系统&#xff08;RDBMS&#xff09;&#xff0c;由瑞典公司 M…

变长的时间戳设计

以前的时间戳有32位&#xff0c;以秒为单位&#xff0c;231秒≈68年&#xff0c;从1970年开始&#xff0c;到2038年会出问题。 后来出现的时间戳有64位&#xff0c;以纳秒为单位&#xff0c;263纳秒≈292年。 本次设计的变长时间戳&#xff0c;以32比特为单位&#xff0c;总共…

“尚泉杯”2024 演讲朗诵公益展演展播在京启动

2024 年 6 月 15 日“尚泉杯”2024 演讲朗诵公益展演展播启动仪式在北京隆重举行。本次活动宗旨是响应领导讲话精神&#xff0c;通过演讲朗诵等形式弘扬中国文化&#xff0c;展现中国魅力&#xff0c;促进文化交流。 活动以“爱我中华”为主体线索&#xff0c;鼓励参与者采用不…

显卡nvidia的CUDA和cuDNN的安装

显卡版本&#xff0c;和nvidia下载的 CUDA版本和CUDNN的关系 1. 显卡版本 nvidia-smi 硬件环境&#xff1a;显卡版本 4090 NVIDIA-SMI-555.85 我的驱动是510.85.02&#xff0c;驱动附带cuda12.5 2. nvidia下载的cuda版本 nvcc -V 我下载的是cuda12.5 cuda在安装版本过程…

新手下白对Latex下手啦!

第一次使用latex&#xff0c;浅浅地记录一下子吧。 首先我们一般会下载一个latex模板&#xff0c;如果想知道咋下载&#xff0c;评论去告诉俺哟&#xff01; 新手小白首先要看懂结构&#xff0c;不然完全下不了手&#xff0c;本文就以IEEE的模板&#xff0c;从头往下讲咯~ 第…

【全网最全最详细】RabbitMQ面试题

一、说下RabbitMQ的架构大致是什么样的&#xff1f; RabbitMQ是一个开源的消息中间件&#xff0c;用于在应用程序之间传递消息。它实现了AMQP&#xff08;高级消息队列协议&#xff09;并支持其它消息传递协议&#xff0c;例如STOMP&#xff08;简单文本定向消息协议&#xff…

动态轮换代理IP是什么?有什么用?

如果您要处理多个在线帐户&#xff0c;选择正确的代理类型对于实现流畅的性能至关重要。但最适合这项工作的代理类型是什么&#xff1f; 为了更好地管理不同平台上的多个账户并优化成本&#xff0c;动态住宅代理IP通常作用在此。 一、什么是轮换代理&#xff1f; 轮换代理充当…

AWR1843BOOST上的TM4C1294NCPDT是干啥用的?

摘要&#xff1a;AWR1843BOOST上面有2个体积较大的芯片&#xff0c;一片是雷达&#xff0c;另一片是什么呢&#xff1f; 答案&#xff1a;它就是XDS110仿真器。 有了它&#xff0c;就不用再买一个仿真器了。 从AWR1843BOOST的原理图中可以看到整个 BOOST板子上只有2个比较大的…

Java实现俄罗斯方块——文本域组件

技术实现&#xff1a; 1.初始化游戏窗口&#xff1b; 2.初始化游戏界面&#xff1b; 3.初始化游戏的说明面板&#xff1b; 4.随机生成下落方块&#xff1b; 5.绘制方块&#xff1b; 6.清除方块&#xff1b; 7.清楚某一行方块&#xff0c;上方方块掉落&#xff1b; 8.刷新…

elementUI的el-table自定义表头

<el-table-column label"昨日仪表里程(KM)" align"left" min-width"190" :render-header"(h, obj) > renderHeader(h, obj, 参数)" > <template slot-scope"scope"> <span>{{ scope.row.firstStartMil…

深度解析响应式异步编程模型

上一篇文章中我们聊了一下线程池,基于线程池的多线程编程是我们在高并发场景下提升系统处理效率的有效手段,但却不是唯一的。今天我们来看一下另一种异步开发的常用手段-响应式编程模型 传统多线程模型的缺陷 多线程模型是目前应用最为广泛的并发编程手段,但凡遇到什么性能…

小摩法兴纷纷转多,看涨港股的时机来了吗?

恒生指数今日高开一度上涨89点报18520点&#xff0c;创近两周高。之后持续震荡下行&#xff1b;恒指临近中 午跌幅扩大&#xff0c;恒生科技指数一度跌近1.5%。截止收盘&#xff0c;恒生指数跌0.52%&#xff0c;盘面上&#xff0c;石油、煤炭、环保、建筑节能等板块涨幅居前&a…

【简易版tinySTL】 vector容器

文章目录 基本概念功能思路代码实现vector.htest.cpp 代码详解变量构造函数析构函数拷贝构造operatorpush_backoperator[]insertprintElements 本实现版本 和 C STL标准库实现版本的区别&#xff1a; 基本概念 vector数据结构和数组非常相似&#xff0c;也称为单端数组vector与…

IP SSL证书使用率大幅度提升

IP SSL证书的使用人数在增长&#xff0c;这一趋势背后有几个推动因素&#xff1a; 1.网络安全意识提升&#xff1a;随着网络安全事件频发&#xff0c;用户和企业对数据保护的重视程度日益增加。IP SSL证书能为基于IP地址直接访问的网站或服务提供加密&#xff0c;有助于防止数据…

深入了解常用负载均衡软件

在构建高性能、高可用的分布式系统时&#xff0c;负载均衡技术扮演着至关重要的角色。它通过合理分发网络请求到后端服务器集群&#xff0c;从而有效提升系统吞吐量、减少响应延迟、并保障系统的稳定运行。本文将介绍几种常用的负载均衡软件&#xff0c;包括它们的优缺点、应用…

高效空气净化器大揭秘,不要再花冤枉钱了!对付“灰尘、毛絮”真好用

最近因为天气炎热的原因&#xff0c;基本上家家户户每天都在开窗通风透气&#xff0c;这就导致很多家庭一直饱受灰尘、毛絮等问题的困扰。 即使天天打扫&#xff0c;家里各处依旧能够找到灰尘、毛絮的踪迹&#xff0c;让很多人苦不堪言。甚至有一部分的灰尘毛絮又聚集在了一些…

C语言中字符串处理函数

目录 前言 1. strlen 测字符串长度函数 2.字符串拷贝函数 2.1strcpy 2.2 strncpy 3.strcat字符串追加函数 4. strcmp/strncmp 比较函数 5.字符查找函数 5.1 strchr 5.2 strrchr 6.atoi/atol/atof字符串转换数值 总结 前言 从0开始记录我的学习历程&#xff0c;我会尽…

Freemaker 模板

背景 发送邮件&#xff0c;正文利用freemaker完成 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId> </dependency>Autowired private Configuration configurer;GetMap…