基于React + TypeScript構建高度可定制的QR碼生成器

前言

在現代Web應用中,QR碼已成為連接線上線下的重要橋梁。本文將詳細介紹如何使用React + TypeScript + Vite構建一個功能強大、高度可定制的QR碼生成器,支持背景圖片、文本疊加、HTML模塊、圓角導出等高級功能。
前往試試

項目概述

技術棧

  • 前端框架: React 19 + TypeScript
  • 構建工具: Vite 6
  • 樣式框架: TailwindCSS 4
  • QR碼生成: qr-code-styling
  • 圖像處理: html2canvas
  • 狀態管理: React Hooks

核心功能

  • 🎨 豐富的QR碼樣式定制(點樣式、顏色、漸變)
  • 🖼? 背景圖片支持(多種適配模式)
  • 📝 文本疊加(字體、顏色、位置可調)
  • 🧩 HTML模塊嵌入
  • 🔄 實時預覽
  • 📤 高質量導出(PNG/JPEG/WebP)
  • 🔄 圓角導出支持
  • ?? 配置參數導入導出

項目架構設計

目錄結構

qr-vite-app-react/
├── src/
│   ├── components/          # React組件
│   │   ├── PreviewCanvas.tsx    # 預覽畫布
│   │   ├── settings/            # 設置面板
│   │   └── test/               # 測試組件
│   ├── hooks/              # 自定義Hooks
│   │   └── useQRGenerator.ts   # QR生成器Hook
│   ├── lib/                # 核心庫
│   │   ├── qr-generator-core.ts # QR生成器核心
│   │   └── package.json        # 獨立包配置
│   ├── types/              # TypeScript類型定義
│   └── utils/              # 工具函數
├── package.json
└── vite.config.ts

核心架構

1. 配置接口設計
interface QRGeneratorConfig {// 基礎配置text: string;width: number;height: number;qrPosition: { x: number; y: number };qrSize: { width: number; height: number };// QR碼樣式qrOptions: {typeNumber: number;mode: 'Numeric' | 'Alphanumeric' | 'Byte' | 'Kanji';errorCorrectionLevel: 'L' | 'M' | 'Q' | 'H';};// 點樣式配置dotsOptions: {color: string;type: 'rounded' | 'dots' | 'classy' | 'square';gradient?: GradientConfig;};// 背景圖片backgrounds?: BackgroundImage[];// 文本疊加texts?: TextLayer[];// HTML模塊htmlModules?: HtmlModule[];// 導出配置exportOptions: {format: 'png' | 'jpeg' | 'webp';quality: number;borderRadius: number;};
}
2. 核心生成器類
export class QRGenerator {private config: QRGeneratorConfig;private container: HTMLDivElement | null = null;private qrCode: any | null = null;private isRendered = false;constructor(config: Partial<QRGeneratorConfig>) {this.config = this.mergeWithDefaults(config);}// 動態創建畫布private createCanvas(): HTMLDivElement {const canvas = document.createElement('div');canvas.style.cssText = `position: relative;width: ${this.config.width}px;height: ${this.config.height}px;background: ${this.config.backgroundOptions.color};overflow: hidden;`;return canvas;}// 添加背景圖片private async addBackgrounds(canvas: HTMLDivElement): Promise<void> {if (!this.config.backgrounds?.length) return;const loadPromises = this.config.backgrounds.map(bg => this.loadBackgroundImage(canvas, bg));await Promise.all(loadPromises);}// 添加QR碼private async addQRCode(canvas: HTMLDivElement): Promise<void> {const QRCodeStyling = await this.loadQRCodeStyling();const qrContainer = document.createElement('div');qrContainer.style.cssText = `position: absolute;left: ${this.config.qrPosition.x}px;top: ${this.config.qrPosition.y}px;width: ${this.config.qrSize.width}px;height: ${this.config.qrSize.height}px;z-index: 100;`;this.qrCode = new QRCodeStyling({width: this.config.qrSize.width,height: this.config.qrSize.height,data: this.config.text,qrOptions: this.config.qrOptions,dotsOptions: this.config.dotsOptions,// ... 其他配置});this.qrCode.append(qrContainer);canvas.appendChild(qrContainer);}// 渲染完整畫布async render(): Promise<HTMLDivElement> {this.container = this.createCanvas();// 添加到DOM(隱藏位置)this.container.style.position = 'absolute';this.container.style.left = '-9999px';document.body.appendChild(this.container);try {await this.addBackgrounds(this.container);await this.addQRCode(this.container);this.addTexts(this.container);this.addHtmlModules(this.container);this.isRendered = true;return this.container;} catch (error) {this.cleanup();throw error;}}// 導出為PNGasync exportAsPNG(options?: ExportOptions): Promise<Blob> {if (!this.isRendered) await this.render();const canvas = await html2canvas(this.container!, {scale: options?.scale || 2,useCORS: true,allowTaint: false,backgroundColor: null,});return new Promise((resolve, reject) => {canvas.toBlob(blob => {blob ? resolve(blob) : reject(new Error('導出失敗'));}, 'image/png', options?.quality || 0.9);});}
}

關鍵技術實現

1. 動態模塊加載

為了解決qr-code-styling的模塊導入問題,采用動態加載策略:

const loadQRCodeStyling = async (): Promise<any> => {try {// 嘗試 ES6 導入const module = await import('qr-code-styling');const QRCodeStyling = module.default || module.QRCodeStyling || module;if (typeof QRCodeStyling !== 'function') {throw new Error('QRCodeStyling is not a constructor');}return QRCodeStyling;} catch (error) {// 回退到 requireconst qrModule = require('qr-code-styling');return qrModule.default || qrModule.QRCodeStyling || qrModule;}
};

2. 背景圖片處理

支持多種適配模式的背景圖片:

private getObjectFitStyle(mode: string): string {const modeMap = {'fill': 'width: 100%; height: 100%;','contain': 'width: 100%; height: 100%; object-fit: contain;','cover': 'width: 100%; height: 100%; object-fit: cover;','stretch': 'width: 100%; height: 100%;'};return modeMap[mode] || modeMap['fill'];
}private async loadBackgroundImage(canvas: HTMLDivElement, bg: BackgroundImage): Promise<void> {return new Promise((resolve, reject) => {const img = document.createElement('img');img.onload = () => {img.style.cssText = `position: absolute;left: ${bg.position.x}px;top: ${bg.position.y}px;width: ${bg.size.width}px;height: ${bg.size.height}px;z-index: ${bg.zIndex};opacity: ${bg.opacity};${this.getObjectFitStyle(bg.mode)}`;canvas.appendChild(img);resolve();};img.onerror = () => reject(new Error(`背景圖片加載失敗: ${bg.src}`));img.src = bg.src;});
}

3. 圓角導出功能

實現圓角導出的核心算法:

private applyRoundedCorners(canvas: HTMLCanvasElement, borderRadius: number): HTMLCanvasElement {if (borderRadius <= 0) return canvas;const roundedCanvas = document.createElement('canvas');const ctx = roundedCanvas.getContext('2d')!;roundedCanvas.width = canvas.width;roundedCanvas.height = canvas.height;// 創建圓角路徑ctx.beginPath();ctx.roundRect(0, 0, canvas.width, canvas.height, borderRadius);ctx.clip();// 繪制原始圖像ctx.drawImage(canvas, 0, 0);return roundedCanvas;
}

4. React Hook集成

使用自定義Hook管理狀態:

export const useQRGenerator = () => {const [qrConfig, setQrConfig] = useState<QRConfig>(defaultQRConfig);const [exportConfig, setExportConfig] = useState<ExportConfig>(defaultExportConfig);const [qrDataUrl, setQrDataUrl] = useState<string>('');const [isGenerating, setIsGenerating] = useState(false);const generateQRCode = useCallback(async () => {setIsGenerating(true);try {const qrCode = new QRCodeStyling({width: 300,height: 300,data: qrConfig.content,qrOptions: qrConfig.qrOptions,dotsOptions: qrConfig.dotsOptions,// ... 其他配置});const dataUrl = await qrCode.getRawData('png');setQrDataUrl(URL.createObjectURL(dataUrl!));} catch (error) {console.error('QR碼生成失敗:', error);} finally {setIsGenerating(false);}}, [qrConfig]);const exportImage = useCallback(async () => {const generator = new QRGenerator({text: qrConfig.content,width: exportConfig.width,height: exportConfig.height,// ... 其他配置});const blob = await generator.exportAsPNG({quality: exportConfig.quality,borderRadius: exportConfig.borderRadius,});// 下載文件const url = URL.createObjectURL(blob);const a = document.createElement('a');a.href = url;a.download = `qr-code-${Date.now()}.png`;a.click();URL.revokeObjectURL(url);}, [qrConfig, exportConfig]);return {qrConfig,setQrConfig,exportConfig,setExportConfig,qrDataUrl,isGenerating,generateQRCode,exportImage,};
};

組件設計

1. 預覽畫布組件

interface PreviewCanvasProps {qrConfig: QRConfig;exportConfig: ExportConfig;qrDataUrl: string;onExport: () => void;isExporting: boolean;
}export const PreviewCanvas: React.FC<PreviewCanvasProps> = ({qrConfig,exportConfig,qrDataUrl,onExport,isExporting
}) => {const [showConfigModal, setShowConfigModal] = useState(false);const [configString, setConfigString] = useState('');const generateConfigString = () => {const config = {qrConfig,exportConfig,timestamp: new Date().toISOString(),};return JSON.stringify(config, null, 2);};const handleExportConfig = () => {const configStr = generateConfigString();setConfigString(configStr);setShowConfigModal(true);};return (<div className="bg-white rounded-lg shadow-lg p-6">{/* 工具欄 */}<div className="flex justify-between items-center mb-4"><h2 className="text-xl font-semibold">預覽</h2><div className="flex gap-2"><buttononClick={handleExportConfig}className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">獲取配置</button><buttononClick={onExport}disabled={isExporting}className="px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600 disabled:opacity-50">{isExporting ? '導出中...' : '導出圖片'}</button></div></div>{/* 畫布容器 */}<div className="border-2 border-dashed border-gray-300 rounded-lg p-4 min-h-[400px] flex items-center justify-center"><divclassName="relative bg-white shadow-lg"style={{width: `${exportConfig.width}px`,height: `${exportConfig.height}px`,borderRadius: `${exportConfig.borderRadius}px`,transform: 'scale(0.5)',transformOrigin: 'center',}}>{/* 背景層 */}{qrConfig.backgrounds.map((bg, index) => (<imgkey={index}src={bg.src}alt={`背景 ${index + 1}`}className="absolute"style={{left: `${bg.position.x}px`,top: `${bg.position.y}px`,width: `${bg.size.width}px`,height: `${bg.size.height}px`,zIndex: bg.zIndex,opacity: bg.opacity,objectFit: bg.mode === 'contain' ? 'contain' : 'cover',}}/>))}{/* QR碼層 */}{qrDataUrl && (<imgsrc={qrDataUrl}alt="QR Code"className="absolute"style={{left: `${qrConfig.qrPosition.x}px`,top: `${qrConfig.qrPosition.y}px`,width: `${qrConfig.qrSize.width}px`,height: `${qrConfig.qrSize.height}px`,zIndex: 100,}}/>)}{/* 文本層 */}{qrConfig.texts.map((text, index) => (<divkey={index}className="absolute whitespace-pre-wrap"style={{left: `${text.position.x}px`,top: `${text.position.y}px`,fontSize: `${text.fontSize}px`,color: text.color,fontFamily: text.fontFamily,fontWeight: text.fontWeight,zIndex: text.zIndex,opacity: text.opacity,textAlign: text.textAlign || 'left',lineHeight: text.lineHeight || 1.2,}}>{text.content}</div>))}{/* HTML模塊層 */}{qrConfig.htmlModules.map((module, index) => (<divkey={index}className="absolute overflow-hidden"style={{left: `${module.position.x}px`,top: `${module.position.y}px`,width: `${module.size.width}px`,height: `${module.size.height}px`,zIndex: module.zIndex,opacity: module.opacity,}}dangerouslySetInnerHTML={{ __html: module.content }}/>))}</div></div>{/* 畫布信息 */}<div className="mt-4 text-sm text-gray-600"><div>畫布尺寸: {exportConfig.width} × {exportConfig.height}px</div><div>圓角半徑: {exportConfig.borderRadius}px</div><div>圖層數量: {qrConfig.backgrounds.length + qrConfig.texts.length + qrConfig.htmlModules.length + 1}</div></div>{/* 配置模態框 */}{showConfigModal && (<ConfigModalconfigString={configString}onClose={() => setShowConfigModal(false)}/>)}</div>);
};

2. 設置面板組件

export const QRSettings: React.FC<QRSettingsProps> = ({qrConfig,onConfigChange
}) => {return (<div className="space-y-6">{/* 基礎設置 */}<div className="bg-white rounded-lg p-4 shadow"><h3 className="text-lg font-semibold mb-4">基礎設置</h3><div className="space-y-4"><div><label className="block text-sm font-medium mb-2">QR碼內容</label><textareavalue={qrConfig.content}onChange={(e) => onConfigChange({ content: e.target.value })}className="w-full p-2 border rounded-md"rows={3}placeholder="輸入要生成QR碼的內容..."/></div><div className="grid grid-cols-2 gap-4"><div><label className="block text-sm font-medium mb-2">QR碼大小</label><inputtype="range"min="100"max="500"value={qrConfig.qrSize.width}onChange={(e) => onConfigChange({qrSize: {width: parseInt(e.target.value),height: parseInt(e.target.value)}})}className="w-full"/><span className="text-sm text-gray-500">{qrConfig.qrSize.width}px</span></div><div><label className="block text-sm font-medium mb-2">容錯級別</label><selectvalue={qrConfig.qrOptions.errorCorrectionLevel}onChange={(e) => onConfigChange({qrOptions: {...qrConfig.qrOptions,errorCorrectionLevel: e.target.value as 'L' | 'M' | 'Q' | 'H'}})}className="w-full p-2 border rounded-md"><option value="L"> (7%)</option><option value="M"> (15%)</option><option value="Q"> (25%)</option><option value="H">最高 (30%)</option></select></div></div></div></div>{/* 樣式設置 */}<div className="bg-white rounded-lg p-4 shadow"><h3 className="text-lg font-semibold mb-4">樣式設置</h3><div className="space-y-4"><div><label className="block text-sm font-medium mb-2">點樣式</label><selectvalue={qrConfig.dotsOptions.type}onChange={(e) => onConfigChange({dotsOptions: {...qrConfig.dotsOptions,type: e.target.value as any}})}className="w-full p-2 border rounded-md"><option value="square">方形</option><option value="rounded">圓角</option><option value="dots">圓點</option><option value="classy">經典</option><option value="extra-rounded">超圓角</option></select></div><div><label className="block text-sm font-medium mb-2">點顏色</label><inputtype="color"value={qrConfig.dotsOptions.color}onChange={(e) => onConfigChange({dotsOptions: {...qrConfig.dotsOptions,color: e.target.value}})}className="w-full h-10 border rounded-md"/></div><div><label className="block text-sm font-medium mb-2">背景顏色</label><inputtype="color"value={qrConfig.backgroundOptions.color}onChange={(e) => onConfigChange({backgroundOptions: {...qrConfig.backgroundOptions,color: e.target.value}})}className="w-full h-10 border rounded-md"/></div></div></div></div>);
};

構建與部署

1. 構建配置

// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from 'path'export default defineConfig({plugins: [react()],resolve: {alias: {'@': path.resolve(__dirname, './src'),'@lib': path.resolve(__dirname, './src/lib')}},optimizeDeps: {include: ['html2canvas', 'qr-code-styling'],},build: {rollupOptions: {output: {manualChunks: {vendor: ['react', 'react-dom'],qr: ['qr-code-styling', 'html2canvas']}}}}
})

2. 獨立庫打包

// src/lib/rollup.config.js
import typescript from '@rollup/plugin-typescript';
import { nodeResolve } from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';export default {input: 'index.ts',output: [{file: 'dist/index.js',format: 'cjs',exports: 'named'},{file: 'dist/index.esm.js',format: 'esm'}],plugins: [nodeResolve({browser: true,preferBuiltins: false}),commonjs({include: ['node_modules/**'],transformMixedEsModules: true}),typescript({tsconfig: './tsconfig.json'})],external: ['qr-code-styling', 'html2canvas']
};

性能優化

1. 懶加載優化

// 組件懶加載
const QRSettings = lazy(() => import('./components/settings/QRSettings'));
const ExportSettings = lazy(() => import('./components/settings/ExportSettings'));// 在使用時
<Suspense fallback={<div>加載中...</div>}><QRSettings {...props} />
</Suspense>

2. 內存管理

export class QRGenerator {// 清理資源cleanup(): void {if (this.container && this.container.parentNode) {this.container.parentNode.removeChild(this.container);}this.container = null;this.qrCode = null;this.isRendered = false;}// 銷毀實例destroy(): void {this.cleanup();// 清理事件監聽器等}
}

3. 緩存策略

// 圖片緩存
const imageCache = new Map<string, HTMLImageElement>();const loadImage = async (src: string): Promise<HTMLImageElement> => {if (imageCache.has(src)) {return imageCache.get(src)!;}return new Promise((resolve, reject) => {const img = new Image();img.onload = () => {imageCache.set(src, img);resolve(img);};img.onerror = reject;img.src = src;});
};

測試與調試

1. 單元測試

// QRGenerator.test.ts
import { QRGenerator } from '../lib/qr-generator-core';describe('QRGenerator', () => {let generator: QRGenerator;beforeEach(() => {generator = new QRGenerator({text: 'Test QR Code',width: 800,height: 600});});afterEach(() => {generator.destroy();});test('should create QR generator with default config', () => {expect(generator.getConfig().text).toBe('Test QR Code');expect(generator.getConfig().width).toBe(800);});test('should render canvas successfully', async () => {const canvas = await generator.render();expect(canvas).toBeInstanceOf(HTMLDivElement);expect(canvas.style.width).toBe('800px');});test('should export PNG blob', async () => {const blob = await generator.exportAsPNG();expect(blob).toBeInstanceOf(Blob);expect(blob.type).toBe('image/png');});
});

2. 集成測試組件

export const QRGeneratorTest: React.FC = () => {const [testResults, setTestResults] = useState<TestResult[]>([]);const [isRunning, setIsRunning] = useState(false);const runTests = async () => {setIsRunning(true);const results: TestResult[] = [];try {// 基礎功能測試const basicTest = await testBasicGeneration();results.push(basicTest);// 導出功能測試const exportTest = await testExportFunctionality();results.push(exportTest);// 配置序列化測試const configTest = await testConfigSerialization();results.push(configTest);} catch (error) {results.push({name: '測試執行失敗',success: false,error: error.message});} finally {setTestResults(results);setIsRunning(false);}};return (<div className="p-6"><h2 className="text-2xl font-bold mb-4">QR生成器測試</h2><buttononClick={runTests}disabled={isRunning}className="px-4 py-2 bg-blue-500 text-white rounded disabled:opacity-50">{isRunning ? '測試中...' : '運行測試'}</button><div className="mt-6 space-y-4">{testResults.map((result, index) => (<divkey={index}className={`p-4 rounded-lg ${result.success ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'}`}><div className="font-semibold">{result.name}</div>{result.error && <div className="text-sm mt-1">{result.error}</div>}{result.duration && <div className="text-sm mt-1">耗時: {result.duration}ms</div>}</div>))}</div></div>);
};

總結

本文詳細介紹了如何構建一個功能完整的QR碼生成器,涵蓋了從架構設計到具體實現的各個方面。主要特點包括:

技術亮點

  1. 模塊化設計: 核心庫可獨立發布使用
  2. TypeScript支持: 完整的類型定義和類型安全
  3. 高度可定制: 支持豐富的樣式和布局選項
  4. 性能優化: 懶加載、緩存、內存管理
  5. 測試完善: 單元測試和集成測試

應用場景

  • 營銷活動二維碼生成
  • 產品包裝二維碼定制
  • 活動海報二維碼嵌入
  • 品牌二維碼標準化生成

擴展方向

  • 支持更多導出格式(SVG、PDF)
  • 添加批量生成功能
  • 集成云存儲服務
  • 支持動態二維碼
  • 添加數據分析功能

如果這篇文章對你有幫助,請點贊收藏支持一下! 🚀

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

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

相關文章

【MATLAB代碼】制導——三點法,二維平面下的例程|運動目標制導,附完整源代碼

三點法制導是一種導彈制導策略,主要用于確保導彈能夠準確追蹤并擊中移動目標。該方法通過計算導彈、目標和制導站之間的相對位置關系,實現對目標的有效制導。 本文給出MATLAB下的三點法例程,模擬平面上捕獲運動目標的情況訂閱專欄后可直接查看源代碼,粘貼到MATLAB空腳本中即…

Ubuntu22.04 安裝 IsaacSim 4.2.0

1. 從官網下載 IsaacSim 4.2.0 安裝包 https://download.isaacsim.omniverse.nvidia.com/isaac-sim-standalone%404.2.0-rc.18%2Brelease.16044.3b2ed111.gl.linux-x86_64.release.zip 2. 查閱 Workstation Installation 安裝方式 Workstation Installation — Isaac Sim Do…

開源量子模擬引擎:Quantum ESPRESSO本地部署教程,第一性原理計算輕松入門!

一、介紹 Quantum ESPRESSO 是一個用于電子結構計算和納米尺度材料建模的開源計算機代碼集成套件&#xff0c;專門用于進行第一性原理&#xff08;第一性原理&#xff09;計算&#xff0c;涵蓋了電子結構、晶體學和材料性能的模擬。 Quantum ESPRESSO GPU 版本支持GPU加速&am…

PVE 虛擬機安裝 Ubuntu Server V24 系統 —— 一步一步安裝配置基于 Ubuntu Server 的 NodeJS 服務器詳細實錄1

前言 最近在基于 NodeJS V22 寫一個全棧的項目&#xff0c;寫好了&#xff0c;當然需要配置服務器部署啦。這個過程對于熟手來說&#xff0c;還是不復雜的&#xff0c;但是對于很多新手來說&#xff0c;可能稍微有點困難。所以&#xff0c;我把整個過程全部記錄一下。 熟悉我…

【JUC】深入解析 JUC 并發編程:單例模式、懶漢模式、餓漢模式、及懶漢模式線程安全問題解析和使用 volatile 解決內存可見性問題與指令重排序問題

單例模式 單例模式確保某個類在程序中只有一個實例&#xff0c;避免多次創建實例&#xff08;禁止多次使用new&#xff09;。 要實現這一點&#xff0c;關鍵在于將類的所有構造方法聲明為private。 這樣&#xff0c;在類外部無法直接訪問構造方法&#xff0c;new操作會在編譯…

2. 庫的操作

2.1 創建數據庫 語法&#xff1a; CREATE DATABASE [IF NOT EXISTS] db_name [create_specification [, create_specification] ...] create_specification: [DEFAULT] CHARACTER SET charset_name # 字符集: 存儲編碼 [DEFAULT] COLLATE collation_name # 校驗集: 比較/選擇/讀…

道可云人工智能每日資訊|北京農業人工智能與機器人研究院揭牌

道可云人工智能&元宇宙每日簡報&#xff08;2025年6月3日&#xff09;訊&#xff0c;今日人工智能&元宇宙新鮮事有&#xff1a; 北京農業人工智能與機器人研究院揭牌 5月30日&#xff0c;北京市農業農村局、北京市海淀區人民政府、北京市農林科學院共同主辦北京農業人…

【JSON-to-Video】設置背景視頻片斷

目錄 設置bgVideo字段 1. 設置bgVideo.videoList字段 2. 設置randomPlay字段 3. 設置complete字段 4. 調用API&#xff0c;制作視頻 歡迎來到JSON轉視頻系列教程。今天要教大家如何添加背景視頻片斷&#xff0c;在視頻制作中&#xff0c;巧妙運用背景視頻&#xff0c;能為…

星閃開發之Server-Client 指令交互控制紅燈亮滅案例解析(SLE_LED詳解)

系列文章目錄 星閃開發之Server-Client 指令交互控制紅燈亮滅的全流程解析&#xff08;SLE_LED詳解&#xff09; 文章目錄 系列文章目錄前言一、項目地址二、客戶端1.SLE_LED_Client\inc\SLE_LED_Client.h2.SLE_LED_Client\src\SLE_LED_Client.c頭文件與依賴管理宏定義與全局變…

Linux shell練習題

Shell 1. 判斷~/bigdata.txt 是否存在&#xff0c;若已存在則打印出”該文件已存在“&#xff0c;如不存在&#xff0c;則輸出打印&#xff1a;”該文件不存在“ if [ -f ./bigdata.txt ];then echo "文件存在" else echo "文件不存在" fi2. 判斷~/bigd…

Linux基本指令(三)

接上之前的文章&#xff0c;咱繼續分享Linux的基本指令&#xff0c;Linux指令比較多&#xff0c;很難全部記住需要做筆記對常用的指令進行記錄&#xff0c;方便以后復習查找&#xff0c;做筆記也可以對知識理解更加深刻。 目錄 時間相關指令 date顯示 時間戳 cal指令 ?編…

WebRTC中sdp多媒體會話協議報文詳細解讀

sdp介紹 在WebRTC&#xff08;Web實時通信&#xff09;中&#xff0c;SDP&#xff08;Session Description Protocol&#xff09;是用來描述和協商多媒體會話的協議。它定義了會話的參數和媒體流的信息&#xff0c;如音視頻編碼格式、傳輸方式、網絡地址等。SDP是WebRTC中一個…

【MySQL】 約束

一、約束的定義 MySQL 約束是用于限制表中數據的規則&#xff0c;確保數據的 準確性 和 一致性 。約束可以在創建表時定義&#xff0c;也可以在表創建后通過修改表結構添加。 二、常見的約束類型 2.1 NOT NULL 非空約束 加了非空約束的列不能為 NULL 值&#xff0c;如果可以…

【.net core】【watercloud】樹形組件combotree導入及調用

源碼下載:combotree: 基于layui及zTree的樹下拉框組件 鏈接中提供了組件的基本使用方法 框架修改內容 1.文件導入&#xff08;路徑可更具自身情況自行設定&#xff09; 解壓后將文件夾放在圖示路徑下&#xff0c;修改文件夾名稱為combotree 2.設置路徑&#xff08;設置layu…

ES101系列07 | 分布式系統和分頁

本篇文章主要講解 ElasticSearch 中分布式系統的概念&#xff0c;包括節點、分片和并發控制等&#xff0c;同時還會提到分頁遍歷和深度遍歷問題的解決方案。 節點 節點是一個 ElasticSearch 示例 其本質就是一個 Java 進程一個機器上可以運行多個示例但生產環境推薦只運行一個…

CppCon 2015 學習:3D Face Tracking and Reconstruction using Modern C++

1. 3D面部追蹤和重建是什么&#xff1f; 3D面部追蹤&#xff08;3D Face Tracking&#xff09;&#xff1a; 實時檢測并追蹤人臉在三維空間中的位置和姿態&#xff08;如轉頭、點頭、表情變化等&#xff09;&#xff0c;通常基于攝像頭捕獲的視頻幀。3D面部重建&#xff08;3D…

代碼中的問題及解決方法

目錄 YOLOX1. AttributeError: VOCDetection object has no attribute cache2. ValueError: operands could not be broadcast together with shapes (8,5) (0,)3. windows遠程查看服務器的tensorboard4. AttributeError: int object has no attribute numel YOLOX 1. Attribu…

【JVM】Java類加載機制

【JVM】Java類加載機制 什么是類加載&#xff1f; 在 Java 的世界里&#xff0c;每一個類或接口在經過編譯后&#xff0c;都會生成對應的 .class 字節碼文件。 所謂類加載機制&#xff0c;就是 JVM 將這些 .class 文件中的二進制數據加載到內存中&#xff0c;并對其進行校驗…

vue的監聽屬性watch的詳解

文章目錄 1. 監聽屬性 watch2. 常規用法3. 監聽對象和route變化4. 使用場景 1. 監聽屬性 watch watch 是一個對象&#xff0c;鍵是需要觀察的表達式&#xff0c;用于觀察 Vue 實例上的一個表達式或者一個函數計算結果的變化。回調函數的參數是新值和舊值。值也可以是方法名&am…

如何在 Ubuntu 24.04 服務器上安裝 Apache Solr

Apache Solr 是一個免費、開源的搜索平臺&#xff0c;廣泛應用于實時索引。其強大的可擴展性和容錯能力使其在高流量互聯網場景下表現優異。 Solr 基于 Java 開發&#xff0c;提供了分布式索引、復制、負載均衡及自動故障轉移和恢復等功能。 本教程將指導您如何在 Ubuntu 24.…