基于 Canvas 的可缩放拖动网格示例(Vue3以及TypeScript )

news2024/9/25 9:18:29

文章目录

  • 1. 基本知识
  • 2. Vue3
  • 3. TypeScript

1. 基本知识

基本知识讲解:

  • Canvas API
    一种用于在网页上绘制图形的 HTML 元素,使用 JavaScript 的 Canvas API 来进行绘制
    使用 getContext('2d') 方法获取 2D 绘图上下文,允许开发者绘制矩形、文本、图像等

  • 缩放和拖动
    通过监听鼠标滚轮事件 (wheel) 可以实现缩放功能,使用 scale 来控制当前缩放比例
    鼠标按下、移动和松开事件实现了拖动功能,允许用户在 Canvas 上自由移动视图

  • 绘制网格
    在 Canvas 上绘制 6 行 26 列的网格,每个区块可以独立显示和命名
    通过动态计算坐标和应用样式,可以实现灵活的绘制效果

  • 响应式设计
    通过 overflow: hiddenposition: relative 样式设置,确保 Canvas 超出部分不会显示,提供良好的用户体验
    鼠标位置计算和缩放中心的设置使得用户操作更加直观和便捷

主要展示如何结合 Vue 3 和 Canvas API 创建一个灵活的用户界面组件,可以用于显示数据、图形或其他可视化内容

用户可以通过鼠标操作与 Canvas 进行交互,提升了整体的使用体验

2. Vue3

以下为完整示例

<template>
  <!-- 鼠标滚轮事件,调用缩放方法 -->
  <!-- 鼠标按下事件,开始拖动 -->
  <!-- 鼠标移动事件,更新拖动位置 -->
  <!-- 鼠标松开事件,结束拖动 -->
  <!-- 设置样式以隐藏溢出部分 -->
  <div
    @wheel.prevent="onWheel"  
    @mousedown="onMouseDown"   
    @mousemove="onMouseMove"   
    @mouseup="onMouseUp"       
    style="overflow: hidden; position: relative;" 
  >
  <!-- 获取 canvas 元素的引用 -->
  <!-- 设置 canvas 宽度 -->
  <!-- 设置 canvas 高度 -->
  <!-- 添加边框样式 -->
    <canvas
      ref="canvas"              
      :width="canvasWidth"     
      :height="canvasHeight"    
      style="border: 1px solid #000;" 
    ></canvas>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue';

// 定义每个区块的接口
interface Block {
  block: string; // 区块名称
  x: number;     // 区块的 X 坐标
  y: number;     // 区块的 Y 坐标
  width: number; // 区块的宽度
  height: number; // 区块的高度
}

// 创建响应式引用
const canvas = ref<HTMLCanvasElement | null>(null); // canvas 引用
const ctx = ref<CanvasRenderingContext2D | null>(null); // canvas 的上下文
const scale = ref(1); // 当前缩放比例
const translatePos = ref({ x: 0, y: 0 }); // 当前偏移位置
const isDragging = ref(false); // 是否正在拖动
const startDragPos = ref({ x: 0, y: 0 }); // 开始拖动时的鼠标位置
const canvasWidth = ref(800); // canvas 初始宽度
const canvasHeight = ref(600); // canvas 初始高度
const options = {
  blockWidth: 30, // 区块宽度
  blockHeight: 30, // 区块高度
  padding: 10, // 区块间距
  startX: 50, // 起始 X 坐标
  startY: 50, // 起始 Y 坐标
};

// 绘制网格
const drawGrid = () => {
  if (!ctx.value) return; // 如果上下文不存在则返回
  
  ctx.value.clearRect(0, 0, canvasWidth.value, canvasHeight.value); // 清空画布
  ctx.value.save(); // 保存当前绘图上下文
  ctx.value.translate(translatePos.value.x, translatePos.value.y); // 应用偏移
  ctx.value.scale(scale.value, scale.value); // 应用缩放

  // 绘制 6 行 26 列的区块
  for (let row = 0; row < 6; row++) {
    for (let col = 0; col < 26; col++) {
      const x = options.startX + col * (options.blockWidth + options.padding); // 计算 X 坐标
      const y = options.startY + row * (options.blockHeight + options.padding); // 计算 Y 坐标
      const block: Block = {
        block: `${row + 1}-${col + 1}`, // 区块名称
        x,
        y,
        width: options.blockWidth,
        height: options.blockHeight,
      };

      drawBlock(block); // 绘制区块
      drawBlockNameText(block); // 绘制区块名称文本
    }
  }

  ctx.value.restore(); // 恢复绘图上下文到之前的状态
};

// 绘制单个区块
const drawBlock = (block: Block) => {
  if (!ctx.value) return; // 如果上下文不存在则返回
  ctx.value.strokeStyle = 'black'; // 设置边框颜色
  ctx.value.lineWidth = 1; // 设置边框宽度
  ctx.value.strokeRect(block.x, block.y, block.width, block.height); // 绘制矩形
};

// 绘制区块名称文本
const drawBlockNameText = (block: Block) => {
  if (!ctx.value) return; // 如果上下文不存在则返回
  ctx.value.font = '10px serif'; // 设置字体
  const textWidth = ctx.value.measureText(block.block).width; // 计算文本宽度
  ctx.value.fillText(
    block.block,
    block.x + (block.width - textWidth) / 2, // 水平居中
    block.y + block.height / 2 + 4 // 垂直居中
  );
};

// 处理鼠标滚轮事件以进行缩放
const onWheel = (event: WheelEvent) => {
  event.preventDefault(); // 阻止默认滚动行为
  const delta = event.deltaY > 0 ? 0.98 : 1.02; // 缩放因子
  const newScale = scale.value * delta; // 计算新的缩放比例
  
  const mousePos = getMousePos(event); // 获取鼠标位置
  const worldPos = {
    x: (mousePos.x - translatePos.value.x) / scale.value, // 计算世界坐标
    y: (mousePos.y - translatePos.value.y) / scale.value,
  };

  // 更新偏移位置,使得缩放以鼠标为中心
  translatePos.value.x = mousePos.x - worldPos.x * newScale;
  translatePos.value.y = mousePos.y - worldPos.y * newScale;
  scale.value = newScale; // 更新缩放比例

  drawGrid(); // 重新绘制内容
};

// 处理鼠标按下事件以开始拖动
const onMouseDown = (event: MouseEvent) => {
  isDragging.value = true; // 设置为正在拖动状态
  startDragPos.value = { x: event.clientX, y: event.clientY }; // 记录起始拖动位置
};

// 处理鼠标移动事件
const onMouseMove = (event: MouseEvent) => {
  if (isDragging.value) { // 如果正在拖动
    const dx = event.clientX - startDragPos.value.x; // 计算 X 轴位移
    const dy = event.clientY - startDragPos.value.y; // 计算 Y 轴位移

    // 更新偏移位置
    translatePos.value.x += dx;
    translatePos.value.y += dy;
    startDragPos.value = { x: event.clientX, y: event.clientY }; // 更新起始拖动位置

    drawGrid(); // 重新绘制内容
  }
};

// 处理鼠标松开事件以结束拖动
const onMouseUp = () => {
  isDragging.value = false; // 设置为不拖动状态
};

// 获取鼠标在 canvas 中的位置
const getMousePos = (event: MouseEvent) => {
  const rect = canvas.value?.getBoundingClientRect(); // 获取 canvas 的边界
  return {
    x: event.clientX - (rect?.left || 0), // 计算 X 坐标
    y: event.clientY - (rect?.top || 0), // 计算 Y 坐标
  };
};

// 在组件挂载后初始化 canvas 和绘制内容
onMounted(() => {
  const canvasElement = canvas.value; // 获取 canvas 元素
  if (canvasElement) {
    ctx.value = canvasElement.getContext('2d'); // 获取 2D 上下文
    drawGrid(); // 初始绘制网格
  }
});
</script>

<style scoped>
/* 鼠标悬停时显示抓取手势 */
canvas {
  cursor: grab; 
}
</style>

截图如下:

在这里插入图片描述

继续升级

<template>
  <div class="canvas-container">
    <canvas
      ref="canvas"
      width="800"
      height="600"
      @wheel="onWheel"
      @mousedown="onMouseDown"
      @mousemove="onMouseMove"
      @mouseup="onMouseUp"
    ></canvas>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue';

// 定义类型
interface MousePosition {
  x: number;
  y: number;
}

interface Block {
  block: string;
  x: number;
  y: number;
  width: number;
  height: number;
}

// Canvas 相关的状态
const canvas = ref<HTMLCanvasElement | null>(null);
const ctx = ref<CanvasRenderingContext2D | null>(null);
const scale = ref(1); // 当前缩放比例
const translatePos = ref<MousePosition>({ x: 0, y: 0 }); // 当前平移位置
const isDragging = ref(false); // 是否正在拖动
const startDragPos = ref<MousePosition>({ x: 0, y: 0 }); // 开始拖动时的鼠标位置

// 网格相关的设置
const options = {
  startX: 50, // 起始 X 坐标
  startY: 50, // 起始 Y 坐标
  blockWidth: 50, // 区块宽度
  blockHeight: 50, // 区块高度
  padding: 0, // 区块间距(设置为0)
};

const canvasWidth = ref(800);
const canvasHeight = ref(600);

// 获取鼠标在 Canvas 上的位置
function getMousePos(event: MouseEvent): MousePosition {
  const rect = canvas.value?.getBoundingClientRect();
  return {
    x: event.clientX - (rect ? rect.left : 0),
    y: event.clientY - (rect ? rect.top : 0),
  };
}

// 滚动缩小放大
function onWheel(event: WheelEvent) {
  event.preventDefault(); // 阻止默认滚动行为
  const mousePos = getMousePos(event);
  const delta = event.deltaY > 0 ? 0.98 : 1.02; // 缩放因子(向下缩小,向上放大)
  const newScale = scale.value * delta; // 计算新的缩放比例

  // 计算新的偏移位置,以鼠标为中心进行缩放
  const worldPos = {
    x: (mousePos.x - translatePos.value.x) / scale.value,
    y: (mousePos.y - translatePos.value.y) / scale.value,
  };

  translatePos.value.x = mousePos.x - worldPos.x * newScale; // 更新平移位置
  translatePos.value.y = mousePos.y - worldPos.y * newScale;
  scale.value = newScale; // 更新缩放比例

  drawInitialContent(); // 重新绘制内容
}

// 鼠标点击
function onMouseDown(event: MouseEvent) {
  isDragging.value = true; // 设置为拖动状态
  startDragPos.value = { x: event.clientX, y: event.clientY }; // 记录开始拖动的鼠标位置
}

// 鼠标移动
function onMouseMove(event: MouseEvent) {
  if (isDragging.value) {
    const dx = event.clientX - startDragPos.value.x; // 计算鼠标移动的距离
    const dy = event.clientY - startDragPos.value.y;

    translatePos.value.x += dx; // 更新平移位置
    translatePos.value.y += dy;

    startDragPos.value = { x: event.clientX, y: event.clientY }; // 更新开始拖动的鼠标位置
    drawInitialContent(); // 重新绘制内容
  }
}

// 鼠标松开
function onMouseUp() {
  isDragging.value = false; // 取消拖动状态
}

// 绘制初始内容
function drawInitialContent() {
  if (ctx.value) {
    ctx.value.clearRect(0, 0, canvasWidth.value, canvasHeight.value); // 清空画布
    ctx.value.save(); // 保存当前的绘图上下文
    ctx.value.translate(translatePos.value.x, translatePos.value.y); // 应用平移
    ctx.value.scale(scale.value, scale.value); // 应用缩放

    drawGrid(); // 绘制网格

    ctx.value.restore(); // 恢复绘图上下文到之前的状态
  }
}

// 绘制网格
const drawGrid = () => {
  if (!ctx.value) return; // 如果上下文不存在则返回
  
  ctx.value.save(); // 保存当前绘图上下文
  ctx.value.translate(translatePos.value.x, translatePos.value.y); // 应用偏移
  ctx.value.scale(scale.value, scale.value); // 应用缩放

  // 绘制 6 行 26 列的区块
  for (let row = 0; row < 6; row++) {
    for (let col = 0; col < 26; col++) {
      const x = options.startX + col * (options.blockWidth + options.padding); // 计算 X 坐标
      const y = options.startY + row * (options.blockHeight + options.padding); // 计算 Y 坐标
      const block: Block = {
        block: `${row + 1}-${col + 1}`, // 区块名称
        x,
        y,
        width: options.blockWidth,
        height: options.blockHeight,
      };

      drawBlock(block); // 绘制区块
      drawBlockNameText(block); // 绘制区块名称文本
    }
  }

  // 绘制边缘数字
  drawEdgeNumbers();

  ctx.value.restore(); // 恢复绘图上下文到之前的状态
};

// 绘制单个区块
const drawBlock = (block: Block) => {
  if (!ctx.value) return; // 如果上下文不存在则返回
  ctx.value.strokeStyle = 'black'; // 设置边框颜色
  ctx.value.lineWidth = 1; // 设置边框宽度
  ctx.value.strokeRect(block.x, block.y, block.width, block.height); // 绘制矩形
};

// 绘制区块名称文本
const drawBlockNameText = (block: Block) => {
  if (!ctx.value) return; // 如果上下文不存在则返回
  ctx.value.font = '10px serif'; // 设置字体
  const textWidth = ctx.value.measureText(block.block).width; // 计算文本宽度
  ctx.value.fillText(
    block.block,
    block.x + (block.width - textWidth) / 2, // 水平居中
    block.y + block.height / 2 + 4 // 垂直居中
  );
};

// 绘制边缘数字
const drawEdgeNumbers = () => {
  // 左侧数字(从0到5)
  for (let row = 0; row < 6; row++) {
    ctx.value!.font = '12px serif';
    ctx.value!.fillText(
      `${row}`,
      options.startX - 20, // 左侧偏移
      options.startY + row * (options.blockHeight + options.padding) + options.blockHeight / 2 + 4 // 垂直居中
    );
  }

  // 下侧数字(奇数,从1到25)
  for (let col = 0; col < 26; col += 2) {
    ctx.value!.font = '12px serif';
    ctx.value!.fillText(
      `${col + 1}`,
      options.startX + col * (options.blockWidth + options.padding) + options.blockWidth / 2 - 8, // 水平居中
      options.startY + 6 * (options.blockHeight + options.padding) + 20 // 下侧偏移
    );
  }
};

// 在组件挂载后初始化
onMounted(() => {
  ctx.value = canvas.value?.getContext('2d'); // 获取 2D 绘图上下文
  drawInitialContent(); // 绘制初始内容
});
</script>

<style scoped>
.canvas-container {
  overflow: hidden; /* 防止超出部分显示 */
  position: relative; /* 相对定位 */
  width: 800px; /* 设置宽度 */
  height: 600px; /* 设置高度 */
}
canvas {
  border: 1px solid #ccc; /* 设置 Canvas 边框 */
}
</style>

截图如下:

在这里插入图片描述

3. TypeScript

只是展示拖拽的一些方法

<template>
  <div class="canvas-container">
    <canvas ref="canvas" width="800" height="600" @wheel="onWheel" @mousedown="onMouseDown" @mousemove="onMouseMove" @mouseup="onMouseUp"></canvas>
  </div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue';

// 定义类型
interface MousePosition {
  x: number;
  y: number;
}

const canvas = ref<HTMLCanvasElement | null>(null);
const ctx = ref<CanvasRenderingContext2D | null>(null);
const scale = ref(1); // 当前缩放比例
const translatePos = ref<MousePosition>({ x: 0, y: 0 }); // 当前平移位置
const isDragging = ref(false); // 是否正在拖动
const startDragPos = ref<MousePosition>({ x: 0, y: 0 }); // 开始拖动时的鼠标位置

// 获取鼠标在 Canvas 上的位置
function getMousePos(event: MouseEvent): MousePosition {
  const rect = canvas.value?.getBoundingClientRect();
  return {
    x: event.clientX - (rect ? rect.left : 0),
    y: event.clientY - (rect ? rect.top : 0),
  };
}

// 滚动缩小放大
function onWheel(event: WheelEvent) {
  event.preventDefault(); // 阻止默认滚动行为
  const mousePos = getMousePos(event);
  const delta = event.deltaY > 0 ? 0.98 : 1.02; // 缩放因子(向下缩小,向上放大)
  const newScale = scale.value * delta; // 计算新的缩放比例

  // 计算新的偏移位置,以鼠标为中心进行缩放
  const worldPos = {
    x: (mousePos.x - translatePos.value.x) / scale.value,
    y: (mousePos.y - translatePos.value.y) / scale.value,
  };

  translatePos.value.x = mousePos.x - worldPos.x * newScale; // 更新平移位置
  translatePos.value.y = mousePos.y - worldPos.y * newScale;
  scale.value = newScale; // 更新缩放比例

  drawInitialContent(); // 重新绘制内容
}

// 鼠标点击
function onMouseDown(event: MouseEvent) {
  isDragging.value = true; // 设置为拖动状态
  startDragPos.value = { x: event.clientX, y: event.clientY }; // 记录开始拖动的鼠标位置
}

// 鼠标移动
function onMouseMove(event: MouseEvent) {
  if (isDragging.value) {
    const dx = event.clientX - startDragPos.value.x; // 计算鼠标移动的距离
    const dy = event.clientY - startDragPos.value.y;

    translatePos.value.x += dx; // 更新平移位置
    translatePos.value.y += dy;

    startDragPos.value = { x: event.clientX, y: event.clientY }; // 更新开始拖动的鼠标位置
    drawInitialContent(); // 重新绘制内容
  }
}

// 鼠标松开
function onMouseUp() {
  isDragging.value = false; // 取消拖动状态
}

// 绘制初始内容
function drawInitialContent() {
  if (ctx.value) {
    ctx.value.clearRect(0, 0, canvas.value!.width, canvas.value!.height); // 清空画布
    ctx.value.save(); // 保存当前的绘图上下文
    ctx.value.translate(translatePos.value.x, translatePos.value.y); // 应用平移
    ctx.value.scale(scale.value, scale.value); // 应用缩放

    // 绘制网格
    drawGrid();

    ctx.value.restore(); // 恢复绘图上下文到之前的状态
  }
}

// 绘制网格
function drawGrid() {
  const rows = 6; // 行数
  const cols = 26; // 列数
  const cellWidth = 30; // 单元格宽度
  const cellHeight = 30; // 单元格高度

  for (let row = 0; row < rows; row++) {
    for (let col = 0; col < cols; col++) {
      const x = col * cellWidth; // 计算 x 坐标
      const y = row * cellHeight; // 计算 y 坐标

      ctx.value!.strokeStyle = 'black'; // 设置边框颜色
      ctx.value!.strokeRect(x, y, cellWidth, cellHeight); // 绘制单元格边框

      // 绘制单元格编号
      ctx.value!.font = '12px Arial';
      ctx.value!.fillStyle = 'black';
      ctx.value!.fillText(`${row + 1}-${col + 1}`, x + 5, y + 20); // 在单元格中间绘制文本
    }
  }
}

// 在组件挂载后初始化
onMounted(() => {
  ctx.value = canvas.value?.getContext('2d'); // 获取 2D 绘图上下文
  drawInitialContent(); // 绘制初始内容
});
</script>

<style scoped>
.canvas-container {
  overflow: hidden; /* 防止超出部分显示 */
  position: relative; /* 相对定位 */
  width: 800px; /* 设置宽度 */
  height: 600px; /* 设置高度 */
}
canvas {
  border: 1px solid #ccc; /* 设置 Canvas 边框 */
}
</style>

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

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

相关文章

MySQL数据库备份详解

文章目录 引言● 数据库备份的重要性 MySQL数据库备份的基础知识● 备份类型1、完全备份2、增量备份3、差异备份 ● 备份工具与方法1、逻辑备份工具——mysqldump2、物理备份工具——Xtrabackup3、第三方解决方案 MySQL数据库备份的实施步骤1、环境准备2、选择合适的备份工具与…

【Linux基础IO】深入解析Linux基础IO缓冲区机制:提升文件操作效率的关键

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ ⏩收录专栏⏪&#xff1a;Linux “ 登神长阶 ” &#x1f921;往期回顾&#x1f921;&#xff1a;暂无 &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀Linux基础IO &#x1f4d2;1. 什么是缓…

14.第二阶段x86游戏实战2-C++语言开发环境搭建-VisualStudio2017

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 本人写的内容纯属胡编乱造&#xff0c;全都是合成造假&#xff0c;仅仅只是为了娱乐&#xff0c;请不要…

基于jsonpath_ng的JSON数据查改增删

jsonpath_ng支持JSON数据的读写操作。 安装 pip install jsonpath-ng测试数据 from jsonpath_ng import parse import jsonjson_data { "store": {"book": [ { "category": "reference","author": "Nigel Rees&qu…

数据集-目标检测系列-鲨鱼检测数据集 shark >> DataBall

数据集-目标检测系列-鲨鱼检测数据集 shark >> DataBall 数据集-目标检测系列-鲨鱼检测数据集 shark 数据量&#xff1a;6k 想要进一步了解&#xff0c;请联系。 DataBall 助力快速掌握数据集的信息和使用方式&#xff0c;百种数据集&#xff0c;持续增加中。 示例&…

【自动驾驶】基于车辆几何模型的横向控制算法 | Stanley 算法详解与编程实现

写在前面&#xff1a; &#x1f31f; 欢迎光临 清流君 的博客小天地&#xff0c;这里是我分享技术与心得的温馨角落。&#x1f4dd; 个人主页&#xff1a;清流君_CSDN博客&#xff0c;期待与您一同探索 移动机器人 领域的无限可能。 &#x1f50d; 本文系 清流君 原创之作&…

【Python】探索 Elpy:Emacs 中的 Python 开发环境

可以短时间不开心&#xff0c;但别长时间不清醒。 对于使用 Emacs 编辑器的 Python 开发者来说&#xff0c;Elpy 是一个强大的集成开发环境&#xff08;IDE&#xff09;&#xff0c;它通过整合多个 Emacs Lisp 和 Python 包&#xff0c;提供了一套完整的 Python 编程支持。本文…

丹摩智算平台体验:AI开发从未如此简单

目录 初次接触丹摩智算GPU算力资源表格 轻松创建GPU实例镜像选择 实验过程体验实验中的一些细节 使用后的感受一点小建议总结 最近我一直在学习一些与深度学习相关的知识&#xff0c;准备自己动手做一些模型训练的实验。平时在自己电脑上跑模型总感觉有点吃力&#xff0c;特别是…

复制他人 CSDN 文章到自己的博客

文章目录 0.前言步骤 0.前言 在复制别人文章发布时&#xff0c;记得表明转载哦 步骤 在需要复制的csdn 文章页面&#xff0c;打开浏览器开发者工具&#xff08;F12&#xff09;Ctrl F 查找"article_content"标签头 右键“Copy”->“Copy element”新建一个 tx…

[大语言模型-论文精读] ACL2024-长尾知识在检索增强型大型语言模型中的作用

ACL2024-长尾知识在检索增强型大型语言模型中的作用 On the Role of Long-tail Knowledge in Retrieval Augmented Large Language Models Authors: Dongyang Li, Junbing Yan, Taolin Zhang, Chengyu Wang, Xiaofeng He, Longtao Huang, Hui Xue, Jun Huang 1.概览 问题解决&…

Windows驱动调试方法

单步调试驱动 驱动的调试不能直接在本机上进行&#xff0c;而是要放在虚拟机&#xff08;或其它设备&#xff09;中。这是因为在内核模式下&#xff0c;一个断点的触发将会停下整个系统而不只是单个进程。 在前面的文章里&#xff0c;使用了DbgPrint函数来进行日志的输出&…

学习一下怎么用git

目录 初始化操作 设置名字&#xff1a; 设置邮箱: 查询状态 初始化本地仓库 清空git bush控制台 git的三个区域 文件提交 将会文件提交到暂存区 暂存指定文件 暂存所有改动文件 查看暂存区里面的文件 将文件提交到版本库 git文件状态查看 ​编辑 暂存区的相关指令…

2024专业U盘格式化数据恢复工具推荐榜

对于经常在不固定办公地点工作&#xff0c;且依赖U盘存储重要资料的朋友来说&#xff0c;U盘无疑成为了随身携带的“数字保险箱”。然而&#xff0c;频繁使用U盘也意味着面临数据丢失的风险。面对u盘格式化怎么恢复数据的难题&#xff0c;您或许正寻求有效的解决方案。接下来&a…

Spring源码-从源码层面讲解传播特性

传播特性:service&#xff1a;REQUIRED&#xff0c;dao:REQUIRED 两个都是required使用的是同一个事务&#xff0c;正常情况&#xff0c;在service提交commit <tx:advice id"myAdvice" transaction-manager"transactionManager"><tx:attributes&…

2024年CSP-J认证 CCF信息学奥赛C++ 中小学初级组 第一轮真题-阅读程序题解析

2024 CCF认证第一轮&#xff08;CSP-J&#xff09;真题 二、阅读程序题 (程序输入不超过数组或字符串定义的范围&#xff0c;判断题正确填√错误填X;除特殊说明外&#xff0c;判断题 1.5分&#xff0c;选择题3分&#xff0c;共计40 分) 第一题 01 #include <iostream>…

【Python】探索 PyTorch 在机器学习中的应用

在机器学习的浪潮中&#xff0c;PyTorch 以其灵活性和易用性成为了研究者和开发者的热门选择。本文将探讨 PyTorch 在机器学习领域的应用&#xff0c;并展示如何使用 PyTorch 构建一个基本的机器学习模型。 ⭕️宇宙起点 &#x1f3ac; 机器学习简介&#x1f4a2; PyTorch 与机…

胤娲科技:AI程序员——重塑编程世界的魔法师

当魔法遇上代码 想象一下&#xff0c;一个对编程一无所知的初中生&#xff0c;在熙熙攘攘的展会现场&#xff0c;仅凭几句简单的提示词&#xff0c;就在几分钟内创造出一个功能完备的倒计时网页。 这听起来像是科幻电影中的场景&#xff0c;但如今&#xff0c;在阿里云「通义灵…

心觉:如何重塑高效学习的潜意识(1)两种方法的优缺点

Hi&#xff0c;我是心觉&#xff0c;与你一起玩转潜意识、脑波音乐和吸引力法则&#xff0c;轻松掌控自己的人生&#xff01; 挑战每日一省写作180/1000天 你的学习习惯是什么呢 学习的时候是感到轻松吗 很多人感觉现在是知识大爆炸的时代&#xff0c;每天都会产生海量的知…

C++学习笔记----8、掌握类与对象(一)---- 对象中的动态内存分配(2)

2.2、用析构函数释放内存 每当完成动态分配内存时&#xff0c;都应该释放。如果在一个对象中动态分配内存&#xff0c;释放内存的地方就是析构函数。编译器保证当对象被破坏时会调用析构函数。下面就是Spreadsheet类定义中的析构函数&#xff1a; export class Spreadsheet { …

秋分之际,又搭建了一款微信记账本小程序

在这个金色的季节里&#xff0c;每一粒粮食都蕴含着生命的奇迹&#xff0c;每一片叶子都在诉说着成长的故事。秋分之际&#xff0c;又搭建了一款微信记账本小程序。 产品概述 微信记账本小程序是一款便捷的个人财务管理工具&#xff0c;旨在帮助用户轻松记录、管理和分析日常…