基于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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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.…