vue3 canvas 選擇器 Canvas 增加頁面性能

文章目錄

  • Vue3 選擇器 Canvas 增加頁面性能
    • 基于Vue3 Composition API和Canvas實現的交互式選擇器,支持PC端和移動端的拖動選擇、多選取消選擇功能
    • vue3組件封裝
    • html代碼

Vue3 選擇器 Canvas 增加頁面性能

基于Vue3 Composition API和Canvas實現的交互式選擇器,支持PC端和移動端的拖動選擇、多選取消選擇功能

在這里插入圖片描述

vue3組件封裝

<script lang="ts" setup>
import { onMounted, reactive, watch } from 'vue';
import { CheckList } from '/@/types';
const props = defineProps({list: {type: Array as PropType<CheckList[]>,default: () => [],},
});
const emit = defineEmits(['changeValue']);// 正確類型定義
const canvas: Ref<HTMLCanvasElement | null> = ref(null);
const ctx: Ref<CanvasRenderingContext2D | null> = ref(null);
// 網格配置
const rows = 8;
const cols = 12;
const rowLabels = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'];
const colLabels = Array.from({ length: 12 }, (_, i) => i + 1);
// 類型定義
type Position = {x: number;y: number;
};
// 狀態管理
const isSelecting = ref(false);
const startPos = ref<Position>({ x: 0, y: 0 });
const endPos = ref<Position>({ x: 0, y: 0 });
const selectionMode = ref('add'); // 'add' 或 'remove'// 選項狀態 (96個選項)
// const options = ref(
//   Array(rows * cols)
//     .fill()
//     .map((_, i) => ({
//       id: `${rowLabels[Math.floor(i / cols)]}${colLabels[i % cols]}`,
//       selected: false,
//     })),
// );
const options = ref([...props.list]);// 計算屬性
const selectedItems = computed(() => options.value.filter((opt) => opt.selected).map((opt) => opt.id));const selectedCount = computed(() => options.value.filter((opt) => opt.selected).length);// 初始化Canvas
const initCanvas = () => {if (canvas.value == null) return;const canvasEl: HTMLCanvasElement = canvas.value;ctx.value = canvasEl.getContext('2d');// 設置Canvas尺寸canvasEl.width = canvasEl.clientWidth;canvasEl.height = canvasEl.clientHeight;drawGrid();
};// 繪制網格和選項
const drawGrid = () => {if (options.value.length == 0 || !canvas.value || !ctx.value) return;const canvasEl = canvas.value;ctx.value.clearRect(0, 0, canvasEl.width, canvasEl.height);// 計算每個選項的尺寸const cellWidth = canvasEl.width / cols;const cellHeight = canvasEl.height / rows;// 繪制網格和選項for (let row = 0; row < rows; row++) {for (let col = 0; col < cols; col++) {const x = col * cellWidth;const y = row * cellHeight;const index = row * cols + col;const isSelected = options.value[index].selected;// 繪制選項背景ctx.value.fillStyle = isSelected ? '#00a9bb' : '#ffffff';ctx.value.fillRect(x, y, cellWidth, cellHeight);// 繪制邊框ctx.value.strokeStyle = isSelected ? '#eeeeee' : '#cccccc';ctx.value.lineWidth = isSelected ? 3 : 1;ctx.value.strokeRect(x, y, cellWidth, cellHeight);// 繪制選項文本ctx.value.fillStyle = isSelected ? '#fff' : '#000000';ctx.value.font = `bold ${cellHeight * 0.3}px Arial`;ctx.value.textAlign = 'center';ctx.value.textBaseline = 'middle';ctx.value.fillText(options.value[index].id, x + cellWidth / 2, y + cellHeight / 2);}}// 繪制行標簽 (1-12)// ctx.value.fillStyle = '#f00';// ctx.value.font = `${12}px`;// for (let col = 0; col < cols; col++) {//   ctx.value.fillText(colLabels[col], (col + 0.5) * cellWidth, cellHeight * 0.2);// }// // 繪制列標簽 (A-H)// for (let row = 0; row < rows; row++) {//   ctx.value.fillText(rowLabels[row].toString(), cellWidth * 0.1, (row + 0.5) * cellHeight);// }// 繪制選擇框if (isSelecting.value) {const x = Math.min(startPos.value.x, endPos.value.x);const y = Math.min(startPos.value.y, endPos.value.y);const width = Math.abs(endPos.value.x - startPos.value.x);const height = Math.abs(endPos.value.y - startPos.value.y);ctx.value.fillStyle = selectionMode.value === 'add' ? 'rgba(100, 200, 255, 0.2)' : 'rgba(255, 100, 100, 0.2)';ctx.value.fillRect(x, y, width, height);ctx.value.strokeStyle = selectionMode.value === 'add' ? 'rgba(100, 200, 255, 0.8)' : 'rgba(255, 100, 100, 0.8)';ctx.value.lineWidth = 2;ctx.value.strokeRect(x, y, width, height);}
};// 獲取Canvas坐標
const getCanvasPos = (event: MouseEvent | TouchEvent) => {if (canvas.value == null) return;const canvasEl: HTMLCanvasElement = canvas.value;const rect = canvasEl.getBoundingClientRect();let clientX: number, clientY: number;// if (event.type.includes('touch')) {if ('touches' in event) {clientX = event.touches[0].clientX;clientY = event.touches[0].clientY;} else {clientX = event.clientX;clientY = event.clientY;}return {x: clientX - rect.left,y: clientY - rect.top,};
};// 開始選擇
const startSelection = (event: MouseEvent | TouchEvent) => {event.preventDefault();const pos: any = getCanvasPos(event);startPos.value = { ...pos };endPos.value = { ...pos };isSelecting.value = true;// 確定選擇模式(添加或移除)if (canvas.value == null) return;const canvasEl: HTMLCanvasElement = canvas.value;const cellWidth = canvasEl.width / cols;const cellHeight = canvasEl.height / rows;const colIndex = Math.floor(pos.x / cellWidth);const rowIndex = Math.floor(pos.y / cellHeight);const index = rowIndex * cols + colIndex;if (index >= 0 && index < options.value.length) {// 如果點擊的選項已選擇,則設為移除模式,否則設為添加模式selectionMode.value = options.value[index].selected ? 'remove' : 'add';// 切換點擊的選項狀態options.value[index].selected = !options.value[index].selected;} else {selectionMode.value = 'add';}drawGrid();
};// 更新選擇
const updateSelection = (event: MouseEvent | TouchEvent) => {if (!isSelecting.value) return;event.preventDefault();const pos: any = getCanvasPos(event);endPos.value = { ...pos };updateSelectedOptions();drawGrid();
};// 結束選擇
const endSelection = (event: MouseEvent | TouchEvent) => {if (!isSelecting.value) return;event.preventDefault();isSelecting.value = false;drawGrid();
};// 更新被選中的選項
const updateSelectedOptions = () => {if (canvas.value == null) return;const canvasEl: HTMLCanvasElement = canvas.value;const cellWidth = canvasEl.width / cols;const cellHeight = canvasEl.height / rows;// 計算選擇框覆蓋的區域const minX = Math.min(startPos.value.x, endPos.value.x);const maxX = Math.max(startPos.value.x, endPos.value.x);const minY = Math.min(startPos.value.y, endPos.value.y);const maxY = Math.max(startPos.value.y, endPos.value.y);// 計算覆蓋的網格范圍const startCol = Math.max(0, Math.floor(minX / cellWidth));const endCol = Math.min(cols - 1, Math.floor(maxX / cellWidth));const startRow = Math.max(0, Math.floor(minY / cellHeight));const endRow = Math.min(rows - 1, Math.floor(maxY / cellHeight));// 更新選項狀態for (let row = startRow; row <= endRow; row++) {for (let col = startCol; col <= endCol; col++) {const index = row * cols + col;if (selectionMode.value === 'add') {options.value[index].selected = true;} else {options.value[index].selected = false;}}}
};
const radioValue = ref('1');
const handleRadio = (e: any) => {if (e.target.value === '1') {selectAll();} else if (e.target.value === '2') {clearSelection();}
};
// 全選
const selectAll = () => {options.value.forEach((opt) => (opt.selected = true));drawGrid();
};// 清空選擇
const clearSelection = () => {options.value.forEach((opt) => (opt.selected = false));drawGrid();
};// 生命周期鉤子
onMounted(() => {initCanvas();window.addEventListener('resize', initCanvas);
});watch(options,(newVal) => {if (newVal.every((item) => item.selected)) {radioValue.value = '1';} else if (newVal.every((item) => !item.selected)) {radioValue.value = '2';} else {radioValue.value = '3';}emit('changeValue', newVal);},{deep: true,},
);
</script><template><div class="box"><canvasref="canvas"@mousedown="startSelection"@mousemove="updateSelection"@mouseup="endSelection"@mouseleave="endSelection"@touchstart="startSelection"@touchmove="updateSelection"@touchend="endSelection"></canvas><div class="mt-20 pl-26"><a-radio-group v-model:value="radioValue" @change="handleRadio" name="radioGroup"><a-radio value="1">全滿</a-radio><a-radio value="2">全空</a-radio></a-radio-group><div mt-10>注:單擊帶藍綠色表示有,單擊顯白色表示無</div></div></div>
</template><style lang="less" scoped>
canvas {width: 450px;height: 300px;background: rgba(10, 15, 30, 0.7);// border-radius: 10px;display: block;cursor: pointer;box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
}
</style>

html代碼


<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Vue3 Canvas 選擇器組件</title><script src="https://unpkg.com/vue@3.2.47/dist/vue.global.js"></script><style>* {margin: 0;padding: 0;box-sizing: border-box;font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;}body {background: linear-gradient(135deg, #1a1a2e, #16213e, #0f3460);min-height: 100vh;display: flex;justify-content: center;align-items: center;padding: 20px;color: #fff;}#app {max-width: 1200px;width: 100%;}.container {display: flex;flex-direction: column;gap: 30px;}header {text-align: center;padding: 30px 20px;background: rgba(255, 255, 255, 0.05);border-radius: 20px;backdrop-filter: blur(10px);border: 1px solid rgba(255, 255, 255, 0.1);box-shadow: 0 15px 35px rgba(0, 0, 0, 0.3);}h1 {font-size: 2.8rem;margin-bottom: 15px;background: linear-gradient(to right, #4facfe, #00f2fe);-webkit-background-clip: text;background-clip: text;color: transparent;}.subtitle {font-size: 1.2rem;opacity: 0.85;max-width: 800px;margin: 0 auto;line-height: 1.6;}.content {display: flex;gap: 30px;flex-wrap: wrap;}.canvas-container {flex: 1;min-width: 300px;background: rgba(255, 255, 255, 0.05);border-radius: 20px;padding: 25px;backdrop-filter: blur(10px);border: 1px solid rgba(255, 255, 255, 0.1);box-shadow: 0 15px 35px rgba(0, 0, 0, 0.3);}canvas {width: 100%;height: 600px;background: rgba(10, 15, 30, 0.8);border-radius: 15px;display: block;cursor: pointer;box-shadow: 0 5px 25px rgba(0, 0, 0, 0.5);}.instructions {font-size: 0.9rem;text-align: center;margin-top: 15px;opacity: 0.8;}.info-panel {width: 320px;background: rgba(255, 255, 255, 0.05);border-radius: 20px;padding: 30px;backdrop-filter: blur(10px);border: 1px solid rgba(255, 255, 255, 0.1);box-shadow: 0 15px 35px rgba(0, 0, 0, 0.3);}.info-panel h2 {font-size: 1.8rem;margin-bottom: 25px;color: #00f2fe;text-align: center;background: linear-gradient(to right, #4facfe, #00f2fe);-webkit-background-clip: text;background-clip: text;color: transparent;}.stats {display: flex;justify-content: space-between;margin-bottom: 30px;padding-bottom: 20px;border-bottom: 1px solid rgba(255, 255, 255, 0.1);}.stat {text-align: center;padding: 15px;background: rgba(0, 0, 0, 0.2);border-radius: 15px;flex: 1;margin: 0 10px;}.stat-value {font-size: 2.5rem;font-weight: bold;color: #4facfe;margin-bottom: 5px;}.stat-label {font-size: 0.95rem;opacity: 0.8;}.selected-items {max-height: 300px;overflow-y: auto;margin-top: 20px;}.selected-items h3 {margin-bottom: 20px;color: #00f2fe;text-align: center;font-size: 1.4rem;}.items-list {display: flex;flex-wrap: wrap;gap: 10px;justify-content: center;}.item {background: linear-gradient(to right, rgba(79, 172, 254, 0.2), rgba(0, 242, 254, 0.2));padding: 8px 15px;border-radius: 25px;font-size: 1rem;border: 1px solid rgba(79, 172, 254, 0.4);}.controls {display: flex;flex-wrap: wrap;gap: 15px;justify-content: center;margin-top: 30px;}button {background: linear-gradient(to right, #4facfe, #00f2fe);color: white;border: none;padding: 12px 30px;border-radius: 30px;font-size: 1rem;font-weight: 600;cursor: pointer;transition: all 0.3s ease;box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);letter-spacing: 0.5px;min-width: 180px;}button:hover {transform: translateY(-3px);box-shadow: 0 8px 20px rgba(0, 0, 0, 0.3);}button:active {transform: translateY(1px);}.empty-message {text-align: center;opacity: 0.6;font-style: italic;margin: 25px 0;padding: 20px;background: rgba(0, 0, 0, 0.15);border-radius: 15px;}.mode-indicator {display: flex;justify-content: center;gap: 20px;margin-top: 15px;}.mode {display: flex;align-items: center;gap: 8px;padding: 8px 16px;border-radius: 20px;background: rgba(0, 0, 0, 0.2);}.mode-color {width: 20px;height: 20px;border-radius: 50%;}.add-color {background: rgba(100, 200, 255, 0.8);}.remove-color {background: rgba(255, 100, 100, 0.8);}.active-mode {background: rgba(79, 172, 254, 0.3);border: 1px solid rgba(79, 172, 254, 0.6);}footer {text-align: center;padding: 25px;opacity: 0.7;font-size: 0.95rem;background: rgba(255, 255, 255, 0.05);border-radius: 20px;backdrop-filter: blur(10px);border: 1px solid rgba(255, 255, 255, 0.1);box-shadow: 0 15px 35px rgba(0, 0, 0, 0.3);}@media (max-width: 768px) {.content {flex-direction: column;}.info-panel {width: 100%;}h1 {font-size: 2.2rem;}canvas {height: 500px;}.stat-value {font-size: 2rem;}}/* 滾動條樣式 */.selected-items::-webkit-scrollbar {width: 8px;}.selected-items::-webkit-scrollbar-track {background: rgba(0, 0, 0, 0.1);border-radius: 4px;}.selected-items::-webkit-scrollbar-thumb {background: linear-gradient(to bottom, #4facfe, #00f2fe);border-radius: 4px;}</style>
</head>
<body><div id="app"><div class="container"><header><h1>Vue3 Canvas 選擇器組件</h1><p class="subtitle">基于Vue3 Composition API和Canvas實現的交互式選擇器,支持PC端和移動端的拖動選擇、多選取消選擇功能</p></header><div class="content"><canvas-selector></canvas-selector></div><footer><p>Vue3 + Canvas 實現 | 支持PC端和移動端 | 拖動選擇多個選項 | 點擊切換選擇模式</p></footer></div></div><script>const { createApp, ref, onMounted, computed, defineComponent } = Vue;const CanvasSelector = defineComponent({setup() {// 引用Canvas元素const canvas = ref(null);const ctx = ref(null);// 網格配置const rows = 12;const cols = 8;const colLabels = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'];const rowLabels = Array.from({ length: 12 }, (_, i) => i + 1);// 狀態管理const isSelecting = ref(false);const startPos = ref({ x: 0, y: 0 });const endPos = ref({ x: 0, y: 0 });const selectionMode = ref('add'); // 'add' 或 'remove'// 選項狀態 (96個選項)const options = ref(Array(rows * cols).fill().map((_, i) => ({id: `${colLabels[i % cols]}${rowLabels[Math.floor(i / cols)]}`,selected: false})));// 計算屬性const selectedItems = computed(() => options.value.filter(opt => opt.selected).map(opt => opt.id));const selectedCount = computed(() => options.value.filter(opt => opt.selected).length);// 初始化Canvasconst initCanvas = () => {const canvasEl = canvas.value;ctx.value = canvasEl.getContext('2d');// 設置Canvas尺寸canvasEl.width = canvasEl.clientWidth;canvasEl.height = canvasEl.clientHeight;drawGrid();};// 繪制網格和選項const drawGrid = () => {const canvasEl = canvas.value;ctx.value.clearRect(0, 0, canvasEl.width, canvasEl.height);// 計算每個選項的尺寸const cellWidth = canvasEl.width / cols;const cellHeight = canvasEl.height / rows;// 繪制網格和選項for (let row = 0; row < rows; row++) {for (let col = 0; col < cols; col++) {const x = col * cellWidth;const y = row * cellHeight;const index = row * cols + col;const isSelected = options.value[index].selected;// 繪制選項背景ctx.value.fillStyle = isSelected ? 'rgba(79, 172, 254, 0.7)' : 'rgba(30, 35, 60, 0.8)';ctx.value.fillRect(x, y, cellWidth, cellHeight);// 繪制邊框ctx.value.strokeStyle = isSelected ? 'rgba(0, 242, 254, 0.9)' : 'rgba(100, 150, 255, 0.3)';ctx.value.lineWidth = isSelected ? 3 : 1;ctx.value.strokeRect(x, y, cellWidth, cellHeight);// 繪制選項文本ctx.value.fillStyle = isSelected ? '#fff' : 'rgba(255, 255, 255, 0.7)';ctx.value.font = `bold ${cellHeight * 0.3}px Arial`;ctx.value.textAlign = 'center';ctx.value.textBaseline = 'middle';ctx.value.fillText(options.value[index].id, x + cellWidth / 2, y + cellHeight / 2);}}// 繪制列標簽 (A-H)ctx.value.fillStyle = 'rgba(200, 220, 255, 0.9)';ctx.value.font = `bold ${cellHeight * 0.25}px Arial`;for (let col = 0; col < cols; col++) {ctx.value.fillText(colLabels[col],(col + 0.5) * cellWidth,cellHeight * 0.2);}// 繪制行標簽 (1-12)for (let row = 0; row < rows; row++) {ctx.value.fillText(rowLabels[row].toString(),cellWidth * 0.2,(row + 0.5) * cellHeight);}// 繪制選擇框if (isSelecting.value) {const x = Math.min(startPos.value.x, endPos.value.x);const y = Math.min(startPos.value.y, endPos.value.y);const width = Math.abs(endPos.value.x - startPos.value.x);const height = Math.abs(endPos.value.y - startPos.value.y);ctx.value.fillStyle = selectionMode.value === 'add' ? 'rgba(100, 200, 255, 0.2)' : 'rgba(255, 100, 100, 0.2)';ctx.value.fillRect(x, y, width, height);ctx.value.strokeStyle = selectionMode.value === 'add' ? 'rgba(100, 200, 255, 0.8)' : 'rgba(255, 100, 100, 0.8)';ctx.value.lineWidth = 2;ctx.value.setLineDash([5, 3]);ctx.value.strokeRect(x, y, width, height);ctx.value.setLineDash([]);}};// 獲取Canvas坐標const getCanvasPos = (event) => {const canvasEl = canvas.value;const rect = canvasEl.getBoundingClientRect();let clientX, clientY;if (event.type.includes('touch')) {clientX = event.touches[0].clientX;clientY = event.touches[0].clientY;} else {clientX = event.clientX;clientY = event.clientY;}return {x: clientX - rect.left,y: clientY - rect.top};};// 開始選擇const startSelection = (event) => {event.preventDefault();const pos = getCanvasPos(event);startPos.value = { ...pos };endPos.value = { ...pos };isSelecting.value = true;// 確定選擇模式(添加或移除)const canvasEl = canvas.value;const cellWidth = canvasEl.width / cols;const cellHeight = canvasEl.height / rows;const colIndex = Math.floor(pos.x / cellWidth);const rowIndex = Math.floor(pos.y / cellHeight);const index = rowIndex * cols + colIndex;if (index >= 0 && index < options.value.length) {// 如果點擊的選項已選擇,則設為移除模式,否則設為添加模式selectionMode.value = options.value[index].selected ? 'remove' : 'add';// 切換點擊的選項狀態options.value[index].selected = !options.value[index].selected;} else {selectionMode.value = 'add';}drawGrid();};// 更新選擇const updateSelection = (event) => {if (!isSelecting.value) return;event.preventDefault();const pos = getCanvasPos(event);endPos.value = { ...pos };updateSelectedOptions();drawGrid();};// 結束選擇const endSelection = (event) => {if (!isSelecting.value) return;event.preventDefault();isSelecting.value = false;drawGrid();};// 更新被選中的選項const updateSelectedOptions = () => {const canvasEl = canvas.value;const cellWidth = canvasEl.width / cols;const cellHeight = canvasEl.height / rows;// 計算選擇框覆蓋的區域const minX = Math.min(startPos.value.x, endPos.value.x);const maxX = Math.max(startPos.value.x, endPos.value.x);const minY = Math.min(startPos.value.y, endPos.value.y);const maxY = Math.max(startPos.value.y, endPos.value.y);// 計算覆蓋的網格范圍const startCol = Math.max(0, Math.floor(minX / cellWidth));const endCol = Math.min(cols - 1, Math.floor(maxX / cellWidth));const startRow = Math.max(0, Math.floor(minY / cellHeight));const endRow = Math.min(rows - 1, Math.floor(maxY / cellHeight));// 更新選項狀態for (let row = startRow; row <= endRow; row++) {for (let col = startCol; col <= endCol; col++) {const index = row * cols + col;if (selectionMode.value === 'add') {options.value[index].selected = true;} else {options.value[index].selected = false;}}}};// 全選const selectAll = () => {options.value.forEach(opt => opt.selected = true);drawGrid();};// 清空選擇const clearSelection = () => {options.value.forEach(opt => opt.selected = false);drawGrid();};// 切換選擇模式const toggleSelectionMode = () => {selectionMode.value = selectionMode.value === 'add' ? 'remove' : 'add';};// 生命周期鉤子onMounted(() => {initCanvas();window.addEventListener('resize', initCanvas);});return {canvas,selectedItems,selectedCount,selectionMode,startSelection,updateSelection,endSelection,selectAll,clearSelection,toggleSelectionMode};},template: `<div class="canvas-container"><canvas ref="canvas" @mousedown="startSelection"@mousemove="updateSelection"@mouseup="endSelection"@mouseleave="endSelection"@touchstart="startSelection"@touchmove="updateSelection"@touchend="endSelection"></canvas><p class="instructions">PC端:點擊并拖動鼠標進行選擇 | 移動端:觸摸并滑動進行選擇</p><div class="mode-indicator"><div class="mode" :class="{ 'active-mode': selectionMode === 'add' }"><div class="mode-color add-color"></div><span>添加模式</span></div><div class="mode" :class="{ 'active-mode': selectionMode === 'remove' }"><div class="mode-color remove-color"></div><span>移除模式</span></div></div></div><div class="info-panel"><h2>選擇信息面板</h2><div class="stats"><div class="stat"><div class="stat-value">{{ selectedCount }}</div><div class="stat-label">已選選項</div></div><div class="stat"><div class="stat-value">96</div><div class="stat-label">總選項</div></div></div><div class="selected-items"><h3>已選選項 ({{ selectedCount }})</h3><div v-if="selectedItems.length > 0" class="items-list"><div v-for="item in selectedItems" :key="item" class="item">{{ item }}</div></div><div v-else class="empty-message">暫無選擇,請在左側區域進行選擇</div></div><div class="controls"><button @click="selectAll">全選</button><button @click="clearSelection">清空</button><button @click="toggleSelectionMode">{{ selectionMode === 'add' ? '切換到移除模式' : '切換到添加模式' }}</button></div></div>`});createApp({components: {CanvasSelector}}).mount('#app');</script>
</body>
</html>

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/914123.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/914123.shtml
英文地址,請注明出處:http://en.pswp.cn/news/914123.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Python 實戰:打造多文件批量重命名工具

引言在實際運維、測試、數據分析、開發流程中&#xff0c;我們經常會處理成百上千條命令操作&#xff0c;例如&#xff1a;各種腳本任務&#xff08;啟動、備份、重啟、日志查看&#xff09;數據處理流程&#xff08;爬取 → 清洗 → 統計 → 可視化&#xff09;配置自動化&…

設計模式筆記_結構型_代理模式

1. 代理模式介紹代理模式是一種結構型設計模式&#xff0c;它允許你提供一個代理對象來控制對另一個對象的訪問。代理對象通常在客戶端和目標對象之間起到中介作用&#xff0c;能夠在不改變目標對象的前提下增加額外的功能操作&#xff0c;比如延遲初始化、訪問控制、日志記錄等…

C語言<數據結構-單鏈表>(收尾)

上篇博客我將基礎的尾插、尾刪、頭插、頭刪逐一講解了&#xff0c;這篇博客將對上篇博客進行收尾&#xff0c;講一下指定位置操作增刪以及查找這幾個函數&#xff0c;其實大同小異&#xff1a;一.查找函數&#xff1a;查找函數其實就是一個簡單的循環遍歷&#xff0c;所以不加以…

十年架構心路:從單機到云原生的分布式系統演進史

十年架構心路&#xff1a;從單機到云原生的分布式系統演進史 這里寫目錄標題十年架構心路&#xff1a;從單機到云原生的分布式系統演進史一、技術生涯的起點&#xff1a;單體架構的黃金時代1.1 典型技術棧1.2 記憶深刻的故障二、分布式架構轉型期2.1 服務化拆分實踐2.2 分布式事…

使用docker搭建nginx

安裝docker 和 docker compose驗證docker版本配置docker目錄配置代理&#xff0c;使docker能訪問外網能否ping通最后直接拉入鏡像即可docker pull nginx

Intel新CPU助攻:微軟Copilot+將登陸臺式電腦

微軟的Copilot PC計劃已經推出一年多&#xff0c;但目前僅支持平板電腦和筆記本電腦&#xff0c;以及少數迷你電腦。 隨著Intel下一代桌面處理器——代號為“Arrow Lake Refresh”的推出&#xff0c;Copilot PC功能有望擴展到桌面計算機。 要支持Copilot PC的所有功能&#xff…

【Kubernetes】跨節點 Pod 網絡不通排查案例

最近在部署一個集群環境的時候&#xff0c;發現集群中一個子節點與其他子節點不通&#xff0c;而 master 節點可與任何子節點互通&#xff0c;通過抓包排查后&#xff0c;發現是 Linux 路由決策導致的。因此&#xff0c;在此記錄下來&#xff0c;希望對大家有所幫助。1、環境及…

【算法訓練營Day11】二叉樹part1

文章目錄理論基礎二叉樹的遞歸遍歷前序遍歷中序遍歷后序遍歷總結二叉樹的層序遍歷基礎層序遍歷二叉樹的右視圖理論基礎 二叉樹在結構上的兩個常用類型&#xff1a; 滿二叉樹完全二叉樹 在功能應用上的比較常用的有&#xff1a; 二叉搜索樹&#xff1a; 節點有權值、遵循”左…

Flutter 之 table_calendar 控件

1.庫導入在pubspec.yaml文件中dev_dependencies:table_calendar: ^3.2.02. 代碼編寫TableCalendar(daysOfWeekHeight: 20,availableGestures: AvailableGestures.horizontalSwipe,firstDay: DateTime.now().subtract(const Duration(days: 365)),lastDay: DateTime.now(),cal…

【leetcode】1486. 數組異或操作

數組異或操作題目題解題目 1486. 數組異或操作 給你兩個整數&#xff0c;n 和 start 。 數組 nums 定義為&#xff1a;nums[i] start 2*i&#xff08;下標從 0 開始&#xff09;且 n nums.length 。 請返回 nums 中所有元素按位異或&#xff08;XOR&#xff09;后得到的…

php7.4使用 new DateTime;報錯 Class DateTime not found

php7.4使用 new DateTime;報錯Uncaught Error: Class ‘app\home\c\DateTime’ not found 查了半天資料&#xff0c;最后找到了解決辦法 DateTime 是 php 內置的類&#xff0c;不隸屬于任何命名空間&#xff0c;如果你需要在命名空間中使用須有 \ 聲明&#xff0c;解決辦法就是…

Gartner《構建可擴展數據產品建設框架》心得

一、背景與價值 1.1 “數據產品”為什么忽然重要? 傳統模式:業務提出需求 → IT 建數據集 → ETL 管道爆炸 → 維護成本指數級上升。 新范式:把“數據”包裝成“產品”,以產品思維迭代演進,強調復用、自助、可擴展。 Gartner 觀察到:大量組織把“報表”或“數據倉庫”重…

CentOS/RHEL LVM 磁盤擴展完整教程

CentOS/RHEL LVM 磁盤擴展完整教程&#x1f4dd; 前言 在Linux系統管理中&#xff0c;磁盤空間不足是經常遇到的問題。特別是在生產環境中&#xff0c;當根分區空間告急時&#xff0c;我們需要通過添加新磁盤來擴展存儲空間。本教程將詳細介紹如何在CentOS/RHEL系統中使用LVM&a…

LVGL應用和部署(用lua做測試)

【 聲明&#xff1a;版權所有&#xff0c;歡迎轉載&#xff0c;請勿用于商業用途。 聯系信箱&#xff1a;feixiaoxing 163.com】嵌入式產品做好了&#xff0c;下面就是測試和量產了。以按鍵屏幕的開發模式為例&#xff0c;如果僅僅是簡單的功能測試&#xff0c;那還比較好解決&…

phpstudy搭建pikachu

一.啟動mysql和nginx服務二.修改靶場文件參數點擊管理打開根目錄&#xff0c;將下載好的靶場源文件解壓到www目錄下三.找到此文件用記事本打開四.修改配置文件五.打開瀏覽器,輸入127.0.0.1/pikachu六.按照步驟初始化心得體會&#xff1a;如果mysql啟動又立刻停止&#xff0c;大…

【Linux】GDB/CGDB 調試器學習筆記

GDB/CGDB 調試器學習筆記&#x1f680; 前言 GDB 是 GNU 項目下功能強大的命令行調試器&#xff0c;適用于 C/C 等多種語言。CGDB 則是在 GDB 之上構建的輕量級 curses 界面&#xff0c;適合喜歡終端操作且習慣 vi 風格的人。一、GDB 入門篇 1. 編譯時帶調試信息 gcc -g -O0 -W…

鏈接代理后無法訪問網絡

路由方向的問題 cmd 輸入 route print 查看路由多了一個不是你網絡的路由 我的嘎嘎好用直接那都通 route add -p 0.0.0.0 mask 0.0.0.0 0.0.0.0 參考這個 固定ip if是代理鏈路的 鏈路口又敏感詞這個文章不合規兩次評論區問我

day37 早停策略和模型權重的保存

DAY 37 我今天的筆記是用cpu訓練的&#xff0c;請自行修改為gpu訓練 仍然是循序漸進&#xff0c;先復習之前的代碼 import torch import torch.nn as nn import torch.optim as optim from sklearn.datasets import load_iris from sklearn.model_selection import train_test_…

網絡爬蟲分類全解析

網絡爬蟲作為數據獲取的重要工具,其分類方式多樣,不同類型的爬蟲在技術實現、應用場景和功能特性上存在顯著差異。深入理解這些分類,有助于開發者根據實際需求選擇合適的爬蟲方案。本文將從技術特性、應用場景和架構設計三個維度,系統介紹網絡爬蟲的主要分類。 一、按技術…

ECR倉庫CloudFormation模板完整指南

概述 本文檔詳細介紹了一個通用的Amazon ECR(Elastic Container Registry)倉庫CloudFormation模板,該模板支持多業務組、參數化配置,并包含完整的安全策略、生命周期管理和監控功能。 模板特性 核心功能 ? 支持4個業務組:app、ai、mall、frontend? 靈活的服務名手動輸…