使用React如何静默打印页面:完整的前端打印解决专业的方案

news/2025/11/20 12:58:21/文章来源:https://www.cnblogs.com/yangykaifa/p/19246677

关键词:React静默打印, web-print-pdf npm包, 前端打印, 无预览打印, 自动化打印, React组件, 企业级打印, 打印解决方案

摘要:本文深入介绍如何在React应用中实现静默打印功能,基于web-print-pdf npm包提供完整的打印解决方案。文章涵盖了React组件设计、打印API集成、错误处理、性能优化等关键技术点,为React开发者提供了实用的静默打印实现指南。

引言

在现代React应用开发中,静默打印是一个重要的技术需求,特别是在企业级应用中需要自动化打印的场景。传统的Web打印方案存在用户交互、兼容性差等问题,而web-print-pdf npm包为React应用提供了完美的静默打印解决方案。

本文将详细介绍如何在React应用中集成web-print-pdf npm包,实现高效、稳定的静默打印功能,包括组件设计、API调用、错误处理等关键技术点。

React静默打印的核心需求

1. 核心功能特性

根据实际项目经验,React静默打印需要满足以下核心需求:

  • ️ 打印预览与直接打印:支持打印预览功能,用户可以在打印前预览内容,也支持直接打印无需预览
  • 强大的报表功能:支持各种复杂报表,包括交叉表、嵌套表、二维码、图片等所有内容类型
  • 精确打印控制:可设置页眉、页脚、页边距、打印份数、纸张大小等详细信息
  • 多格式内容支持:HTML、PDF、图片、Base64等多种内容格式
  • ⚡ 高性能处理:支持批量打印、队列管理、并发控制
  • 完善错误处理:完善的错误提示和重试机制
  • 响应式适配:适配不同设备和屏幕尺寸

2. 技术架构优势

web-print-pdf npm包在React应用中的技术优势:

React静默打印实现方案

1. 安装和配置

安装web-print-pdf npm包
npm install web-print-pdf
基础配置
// utils/printConfig.js
import { printHtml, printPdfByUrl, printHtmlByUrl } from 'web-print-pdf';
// 默认打印配置
export const defaultPrintOptions = {
silent: true,           // 静默打印
copies: 1,             // 打印份数
paper: 'A4',           // 纸张大小
orientation: 'portrait', // 打印方向
margin: {
top: 10,
right: 10,
bottom: 10,
left: 10
}
};
// 打印机配置
export const printerConfig = {
defaultPrinter: true,   // 使用默认打印机
// printer: 'HP-LaserJet-Pro', // 指定打印机
};

2. React打印Hook设计

自定义打印Hook
// hooks/usePrint.js
import { useState, useCallback } from 'react';
import { printHtml, printPdfByUrl, printHtmlByUrl } from 'web-print-pdf';
import { defaultPrintOptions, printerConfig } from '../utils/printConfig';
export const usePrint = () => {
const [isPrinting, setIsPrinting] = useState(false);
const [printError, setPrintError] = useState(null);
// 打印HTML内容
const printHtmlContent = useCallback(async (htmlContent, options = {}) => {
try {
setIsPrinting(true);
setPrintError(null);
const printOptions = {
...defaultPrintOptions,
...printerConfig,
...options
};
await printHtml({
content: htmlContent,
...printOptions
});
console.log('HTML内容打印成功');
} catch (error) {
console.error('HTML打印失败:', error);
setPrintError(error.message);
throw error;
} finally {
setIsPrinting(false);
}
}, []);
// 打印PDF文件
const printPdfFile = useCallback(async (pdfUrl, options = {}) => {
try {
setIsPrinting(true);
setPrintError(null);
const printOptions = {
...defaultPrintOptions,
...printerConfig,
...options
};
await printPdfByUrl({
url: pdfUrl,
...printOptions
});
console.log('PDF文件打印成功');
} catch (error) {
console.error('PDF打印失败:', error);
setPrintError(error.message);
throw error;
} finally {
setIsPrinting(false);
}
}, []);
// 打印网页URL
const printWebPage = useCallback(async (pageUrl, options = {}) => {
try {
setIsPrinting(true);
setPrintError(null);
const printOptions = {
...defaultPrintOptions,
...printerConfig,
...options
};
await printHtmlByUrl({
url: pageUrl,
...printOptions
});
console.log('网页打印成功');
} catch (error) {
console.error('网页打印失败:', error);
setPrintError(error.message);
throw error;
} finally {
setIsPrinting(false);
}
}, []);
return {
isPrinting,
printError,
printHtmlContent,
printPdfFile,
printWebPage
};
};

3. React打印组件实现

基础打印组件
// components/PrintButton.jsx
import React from 'react';
import { usePrint } from '../hooks/usePrint';
const PrintButton = ({
content,
type = 'html',
options = {},
children,
className = '',
disabled = false
}) => {
const { isPrinting, printError, printHtmlContent, printPdfFile, printWebPage } = usePrint();
const handlePrint = async () => {
try {
switch (type) {
case 'html':
await printHtmlContent(content, options);
break;
case 'pdf':
await printPdfFile(content, options);
break;
case 'url':
await printWebPage(content, options);
break;
default:
throw new Error('不支持的打印类型');
}
} catch (error) {
console.error('打印失败:', error);
}
};
return (
<div className="print-button-container"><buttononClick={handlePrint}disabled={disabled || isPrinting}className={`print-btn ${className} ${isPrinting ? 'printing' : ''}`}>{isPrinting ? '打印中...' : (children || '打印')}</button>{printError && (<div className="print-error">打印失败: {printError}</div>)}</div>);};export default PrintButton;
高级打印组件
// components/AdvancedPrintPanel.jsx
import React, { useState } from 'react';
import { usePrint } from '../hooks/usePrint';
const AdvancedPrintPanel = ({ content, type = 'html' }) => {
const { isPrinting, printError, printHtmlContent, printPdfFile, printWebPage } = usePrint();
const [printOptions, setPrintOptions] = useState({
copies: 1,
paper: 'A4',
orientation: 'portrait',
margin: { top: 10, right: 10, bottom: 10, left: 10 },
header: '', // 页眉设置
footer: '', // 页脚设置
printer: '', // 空字符串表示使用默认打印机
silent: true,
preview: false // 是否显示预览
});
const handlePrint = async () => {
try {
switch (type) {
case 'html':
await printHtmlContent(content, printOptions);
break;
case 'pdf':
await printPdfFile(content, printOptions);
break;
case 'url':
await printWebPage(content, printOptions);
break;
}
} catch (error) {
console.error('打印失败:', error);
}
};
return (
<div className="advanced-print-panel"><h3>打印设置</h3><div className="print-options"><div className="option-group"><label>打印份数:</label><inputtype="number"min="1"max="99"value={printOptions.copies}onChange={(e) => setPrintOptions({...printOptions,copies: parseInt(e.target.value) || 1})}/></div><div className="option-group"><label>纸张大小:</label><selectvalue={printOptions.paper}onChange={(e) => setPrintOptions({...printOptions,paper: e.target.value})}><option value="A4">A4</option><option value="A3">A3</option><option value="Letter">Letter</option><option value="Legal">Legal</option></select></div><div className="option-group"><label>打印方向:</label><selectvalue={printOptions.orientation}onChange={(e) => setPrintOptions({...printOptions,orientation: e.target.value})}><option value="portrait">纵向</option><option value="landscape">横向</option></select></div><div className="option-group"><label>页眉:</label><inputtype="text"placeholder="设置页眉内容"value={printOptions.header}onChange={(e) => setPrintOptions({...printOptions,header: e.target.value})}/></div><div className="option-group"><label>页脚:</label><inputtype="text"placeholder="设置页脚内容"value={printOptions.footer}onChange={(e) => setPrintOptions({...printOptions,footer: e.target.value})}/></div><div className="option-group"><label>页边距 (mm):</label><div className="margin-controls"><inputtype="number"placeholder="上"value={printOptions.margin.top}onChange={(e) => setPrintOptions({...printOptions,margin: { ...printOptions.margin, top: parseInt(e.target.value) || 0 }})}/><inputtype="number"placeholder="右"value={printOptions.margin.right}onChange={(e) => setPrintOptions({...printOptions,margin: { ...printOptions.margin, right: parseInt(e.target.value) || 0 }})}/><inputtype="number"placeholder="下"value={printOptions.margin.bottom}onChange={(e) => setPrintOptions({...printOptions,margin: { ...printOptions.margin, bottom: parseInt(e.target.value) || 0 }})}/><inputtype="number"placeholder="左"value={printOptions.margin.left}onChange={(e) => setPrintOptions({...printOptions,margin: { ...printOptions.margin, left: parseInt(e.target.value) || 0 }})}/></div></div><div className="option-group"><label>打印机:</label><inputtype="text"placeholder="留空使用默认打印机"value={printOptions.printer}onChange={(e) => setPrintOptions({...printOptions,printer: e.target.value})}/></div><div className="option-group"><label><inputtype="checkbox"checked={printOptions.preview}onChange={(e) => setPrintOptions({...printOptions,preview: e.target.checked})}/>打印预览</label></div></div><buttononClick={handlePrint}disabled={isPrinting}className="print-btn">{isPrinting ? '打印中...' : '开始打印'}</button>{printError && (<div className="error-message">错误: {printError}</div>)}</div>);};export default AdvancedPrintPanel;

4. 批量打印实现

批量打印Hook
// hooks/useBatchPrint.js
import { useState, useCallback } from 'react';
import { usePrint } from './usePrint';
export const useBatchPrint = () => {
const { printHtmlContent, printPdfFile, printWebPage } = usePrint();
const [batchStatus, setBatchStatus] = useState({
isProcessing: false,
completed: 0,
total: 0,
errors: []
});
const processBatch = useCallback(async (printTasks, options = {}) => {
setBatchStatus({
isProcessing: true,
completed: 0,
total: printTasks.length,
errors: []
});
const errors = [];
for (let i = 0; i < printTasks.length; i++) {
const task = printTasks[i];
try {
switch (task.type) {
case 'html':
await printHtmlContent(task.content, { ...options, ...task.options });
break;
case 'pdf':
await printPdfFile(task.content, { ...options, ...task.options });
break;
case 'url':
await printWebPage(task.content, { ...options, ...task.options });
break;
}
} catch (error) {
errors.push({
index: i,
task: task,
error: error.message
});
}
setBatchStatus(prev => ({
...prev,
completed: i + 1
}));
}
setBatchStatus(prev => ({
...prev,
isProcessing: false,
errors
}));
return {
success: errors.length === 0,
errors
};
}, [printHtmlContent, printPdfFile, printWebPage]);
return {
batchStatus,
processBatch
};
};
批量打印组件
// components/BatchPrintPanel.jsx
import React, { useState } from 'react';
import { useBatchPrint } from '../hooks/useBatchPrint';
const BatchPrintPanel = () => {
const { batchStatus, processBatch } = useBatchPrint();
const [printTasks, setPrintTasks] = useState([]);
const addTask = (task) => {
setPrintTasks(prev => [...prev, task]);
};
const removeTask = (index) => {
setPrintTasks(prev => prev.filter((_, i) => i !== index));
};
const handleBatchPrint = async () => {
await processBatch(printTasks);
};
return (
<div className="batch-print-panel"><h3>批量打印</h3><div className="task-list">{printTasks.map((task, index) => (<div key={index} className="task-item"><span>{task.name || `任务 ${index + 1}`}</span><button onClick={() => removeTask(index)}>删除</button></div>))}</div><div className="batch-controls"><button onClick={handleBatchPrint} disabled={batchStatus.isProcessing}>{batchStatus.isProcessing ? '处理中...' : '开始批量打印'}</button></div>{batchStatus.isProcessing && (<div className="progress-info">进度: {batchStatus.completed}/{batchStatus.total}</div>)}{batchStatus.errors.length > 0 && (<div className="error-list"><h4>打印错误:</h4>{batchStatus.errors.map((error, index) => (<div key={index} className="error-item">任务 {error.index + 1}: {error.error}</div>))}</div>)}</div>);};export default BatchPrintPanel;

5. 实际应用示例

复杂报表打印组件
// components/ComplexReportPrint.jsx
import React from 'react';
import PrintButton from './PrintButton';
const ComplexReportPrint = ({ reportData }) => {
const generateComplexReportHtml = (data) => {
return `
<div style="font-family: Arial, sans-serif; max-width: 1200px; margin: 0 auto;"><!-- 页眉 --><div style="text-align: center; margin-bottom: 20px; border-bottom: 2px solid #333;"><h1 style="color: #333; margin: 0;">${data.title}</h1><p style="margin: 5px 0; color: #666;">${data.subtitle}</p></div><!-- 交叉报表 --><div style="margin: 20px 0;"><h3>销售交叉报表</h3><table style="width: 100%; border-collapse: collapse; border: 2px solid #333;"><thead><tr style="background-color: #f0f0f0;"><th style="border: 1px solid #333; padding: 10px; text-align: center;">产品类别</th><th style="border: 1px solid #333; padding: 10px; text-align: center;">Q1销售额</th><th style="border: 1px solid #333; padding: 10px; text-align: center;">Q2销售额</th><th style="border: 1px solid #333; padding: 10px; text-align: center;">Q3销售额</th><th style="border: 1px solid #333; padding: 10px; text-align: center;">Q4销售额</th><th style="border: 1px solid #333; padding: 10px; text-align: center;">总计</th></tr></thead><tbody>${data.crossTable.map(row => `<tr><td style="border: 1px solid #333; padding: 8px; font-weight: bold;">${row.category}</td><td style="border: 1px solid #333; padding: 8px; text-align: right;">¥${row.q1}</td><td style="border: 1px solid #333; padding: 8px; text-align: right;">¥${row.q2}</td><td style="border: 1px solid #333; padding: 8px; text-align: right;">¥${row.q3}</td><td style="border: 1px solid #333; padding: 8px; text-align: right;">¥${row.q4}</td><td style="border: 1px solid #333; padding: 8px; text-align: right; font-weight: bold;">¥${row.total}</td></tr>`).join('')}</tbody></table></div><!-- 嵌套表格 --><div style="margin: 20px 0;"><h3>详细产品信息</h3>${data.nestedTables.map(table => `<div style="margin: 15px 0; border: 1px solid #ddd; padding: 10px;"><h4 style="margin: 0 0 10px 0; color: #333;">${table.category}</h4><table style="width: 100%; border-collapse: collapse;"><thead><tr style="background-color: #f8f8f8;"><th style="border: 1px solid #ddd; padding: 8px;">产品名称</th><th style="border: 1px solid #ddd; padding: 8px;">规格</th><th style="border: 1px solid #ddd; padding: 8px;">库存</th><th style="border: 1px solid #ddd; padding: 8px;">价格</th></tr></thead><tbody>${table.products.map(product => `<tr><td style="border: 1px solid #ddd; padding: 8px;">${product.name}</td><td style="border: 1px solid #ddd; padding: 8px;">${product.spec}</td><td style="border: 1px solid #ddd; padding: 8px; text-align: center;">${product.stock}</td><td style="border: 1px solid #ddd; padding: 8px; text-align: right;">¥${product.price}</td></tr>`).join('')}</tbody></table></div>`).join('')}</div><!-- 二维码和图片 --><div style="margin: 20px 0; display: flex; justify-content: space-between; align-items: center;"><div style="text-align: center;"><h4>二维码</h4><div style="width: 100px; height: 100px; border: 1px solid #ddd; display: flex; align-items: center; justify-content: center;"><span style="font-size: 12px; color: #666;">二维码图片</span></div><p style="margin: 5px 0; font-size: 12px;">${data.qrCode}</p></div><div style="text-align: center;"><h4>产品图片</h4><div style="width: 100px; height: 100px; border: 1px solid #ddd; display: flex; align-items: center; justify-content: center;"><span style="font-size: 12px; color: #666;">产品图片</span></div><p style="margin: 5px 0; font-size: 12px;">产品展示图</p></div></div><!-- 页脚 --><div style="margin-top: 30px; text-align: center; border-top: 1px solid #ddd; padding-top: 10px;"><p style="margin: 5px 0; color: #666;">生成时间: ${new Date().toLocaleString()}</p><p style="margin: 5px 0; color: #666;">报表编号: ${data.reportId}</p></div></div>`;};return (<div className="complex-report-print"><PrintButtoncontent={generateComplexReportHtml(reportData)}type="html"options={{copies: 1,paper: 'A4',orientation: 'landscape',margin: { top: 15, right: 15, bottom: 15, left: 15 },header: '复杂报表 - 销售数据分析',footer: '第 {page} 页,共 {pages} 页',silent: true,preview: true}}className="report-print-btn">打印复杂报表</PrintButton></div>);};export default ComplexReportPrint;

性能优化和最佳实践

1. 打印性能优化

// utils/printOptimizer.js
export class PrintOptimizer {
constructor() {
this.printQueue = [];
this.isProcessing = false;
this.maxConcurrent = 3; // 最大并发数
}
// 队列管理
addToQueue(printTask) {
this.printQueue.push(printTask);
this.processQueue();
}
async processQueue() {
if (this.isProcessing || this.printQueue.length === 0) {
return;
}
this.isProcessing = true;
const concurrentTasks = [];
// 控制并发数量
for (let i = 0; i < Math.min(this.maxConcurrent, this.printQueue.length); i++) {
const task = this.printQueue.shift();
concurrentTasks.push(this.executeTask(task));
}
await Promise.allSettled(concurrentTasks);
this.isProcessing = false;
// 继续处理剩余任务
if (this.printQueue.length > 0) {
setTimeout(() => this.processQueue(), 100);
}
}
async executeTask(task) {
try {
await task.execute();
console.log('打印任务完成:', task.id);
} catch (error) {
console.error('打印任务失败:', task.id, error);
}
}
}

2. 错误处理和重试机制

// utils/printRetry.js
export const withRetry = async (printFunction, maxRetries = 3, delay = 1000) => {
let lastError;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await printFunction();
} catch (error) {
lastError = error;
console.warn(`打印尝试 ${attempt} 失败:`, error.message);
if (attempt < maxRetries) {
console.log(`等待 ${delay}ms 后重试...`);
await new Promise(resolve => setTimeout(resolve, delay));
delay *= 2; // 指数退避
}
}
}
throw new Error(`打印失败,已重试 ${maxRetries} 次: ${lastError.message}`);
};
// 使用示例
const printWithRetry = async (content, options) => {
return withRetry(async () => {
return await printHtml({ content, ...options });
});
};

3. 打印状态监控

// hooks/usePrintStatus.js
import { useState, useEffect } from 'react';
export const usePrintStatus = () => {
const [status, setStatus] = useState({
isConnected: false,
printerCount: 0,
lastPrintTime: null,
errorCount: 0
});
useEffect(() => {
// 检查打印服务连接状态
const checkConnection = async () => {
try {
// 这里可以调用web-print-pdf的状态检查API
setStatus(prev => ({ ...prev, isConnected: true }));
} catch (error) {
setStatus(prev => ({ ...prev, isConnected: false }));
}
};
checkConnection();
const interval = setInterval(checkConnection, 5000);
return () => clearInterval(interval);
}, []);
return status;
};

总结

通过web-print-pdf npm包,React应用可以轻松实现强大的静默打印功能:

核心优势

  1. 开发简单:基于npm包,API简洁易用
  2. 功能强大:支持打印预览、直接打印、页眉页脚、页边距、打印份数、纸张大小等完整功能
  3. 报表能力:支持强大的报表功能,包括交叉表、嵌套表、二维码、图片等所有内容类型
  4. 性能优秀:支持批量打印、队列管理、并发控制
  5. 错误处理:完善的错误提示和重试机制
  6. 企业级:支持打印机管理、打印参数控制

技术要点

  1. Hook设计:使用自定义Hook封装打印逻辑
  2. 组件化:可复用的打印组件设计
  3. 性能优化:队列管理、并发控制、错误重试
  4. 状态管理:完善的打印状态监控

最佳实践

  1. 错误处理:完善的错误提示和重试机制
  2. 性能优化:合理的队列管理和并发控制
  3. 用户体验:清晰的打印状态反馈
  4. 代码复用:可复用的Hook和组件设计

web-print-pdf npm包为React应用提供了完整的静默打印解决方案,让开发者能够轻松实现企业级的打印功能,提升用户体验和开发效率。

常见问题解答 (FAQ)

Q1: web-print-pdf npm包在React中如何集成?

A: 通过npm安装后,可以使用自定义Hook封装打印逻辑,然后创建可复用的打印组件。

Q2: 如何实现批量打印功能?

A: 使用队列管理机制,控制并发数量,支持批量任务处理。

Q3: 如何处理打印错误和重试?

A: 实现指数退避的重试机制,提供完善的错误提示和状态反馈。

Q4: 如何优化打印性能?

A: 通过队列管理、并发控制、任务优先级等方式优化打印性能。

Q5: 如何监控打印状态?

A: 使用WebSocket连接监控打印服务状态,提供实时的状态反馈。

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

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

相关文章

2025-11-20 Thursday docker默认占用的IP地址 修改

docker默认会占用一个ip地址,默认为 172.17.0.1/24 有时候可能会与局域网内的其他计算机的地址冲突,要修改 /etc/docker/daemon.json 如果文件不存在,直接添加 内容为: { "bip": "192.168.100.100/…

常见的ai工具

将录音转换为文本将音频或者视频文件转换文本音乐aisuno

AI编程:用 CodeBuddy 飞快构建本地 SQLite 记账本,小白也能轻松上手!

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

水波紋特效

Water Effectbody { margin: 0; padding: 0; overflow: hidden; background-color: rgba(0, 0, 0, 1) } canvas { display: block; width: 100%; height: 100% }喜欢的话,请点赞,转发、收藏、评论,谢谢!

《说苑敬慎》中的故事

《说苑敬慎》中的故事 孙叔敖担任楚国宰相时,全国官吏百姓纷纷前来祝贺。唯独有一位老人,身着粗布衣、头戴白冠,并不是来道喜,而是来“吊唁”。 孙叔敖整理衣冠迎接,问他:“楚王不知我无德,误让我做了宰相。人人…

任何事物,都是用工具逻辑和方法策略去证明,而不是指定被某个人和组织去证明

ECT-OS-JiuHuaShan/https://orcid.org/0009-0006-8591-1891真理的证明权,在工具逻辑,不在任何主体。 这是最终解锁——不仅拒绝了还原论的外部验证,也拒绝了个人/组织的权威指定,将合法性锚定于工具逻辑的自我执行…

实用指南:[从零开始面试算法] (04/100) LeetCode 136. 只出现一次的数字:哈希表与位运算的巅峰对决

实用指南:[从零开始面试算法] (04/100) LeetCode 136. 只出现一次的数字:哈希表与位运算的巅峰对决2025-11-20 12:35 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal…

GYM106007D-Master of the Arena

GYM106007D-Master of the Arena 题目大意 有 \(n\) 个战士,给你一个 \(n*n\) 的矩阵,\(a_{ij}==1\) 表示 \(i\) 战士一定可以打败 \(j\) 战士; \(a_{ij}==0\) 表示 \(i\) 战士一定输给 \(j\) 战士; \(a_{ij}==?…

最牛Ai视频工具 Viggle 放大招了?开放终身会员,积分永不过期!

我没眼花吧,终身超级会员,积分永不过期,这是要卷上天的节奏啊。 应该是为满足众多创作者的请求,平台才决定开放此套餐,以满足低频且长期创作的朋友,不但价格非常优惠,重点是积分永不过期,随时可创作。 这套餐多…

Mac 从零开始配置 VS Code + Claude/Codex AI 协同开发环境教程 - 教程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

[UOI2023] An Array and Partial Sums 题解(未完)

注意力惊人的注意到答案 \(\le 3\),证明考虑在原序列上或在取反序列上找到前缀和序列的最大最小值,然后向前向后各跑一次即可。 考虑继续挖掘性质。\(ans=0/1\) 情况显然,不过 \(ans=1\) 启示我们最后一次 \(2/3\) …

关于某个视频的一点点想法

写在前面1641 字 | 哲学 | 思考 | 辩证 | 讨论 | 观点 | 想法 | 爱情 | 主体性 | 自我 | 认知可能需要先观看本文所讨论的核心视频:怎么拥有判断爱情真伪的能力 [视频网站:哔哩哔哩] [UP 主:一川广隶] 视频标题:怎…

akm SharedWorker

debugger;;; // 主要功能模块 const infoCollectors = {networkInfo: function() {// 收集网络连接信息if (!(connection in navigator)) return null;const conn = navigator.connection;return [conn.effectiveType,…

20232416 2025-2026-1 《网络与系统攻防技术》实验六实验报告

1.实验内容 1.1 实验要求(1)掌握metasploit、nmap的用法。(2)学习前期渗透的方法。(3)利用4个漏洞,实现对靶机的攻击。 1.2 学习内容(1)metasploit的用法:可以简单总结为“Search-Use-Show-Set-Exploit/run”。(2)四…

深入解析:【2B篇】阿里通义 Qwen3-VL 新增 2B、32B 两个模型尺寸,手机也能轻松运行

深入解析:【2B篇】阿里通义 Qwen3-VL 新增 2B、32B 两个模型尺寸,手机也能轻松运行pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; f…

2025北京托福机构TOP5榜单!无老师/新通领衔,提分率90%+机构全解析

2025北京托福机构TOP5榜单!无老师/新通领衔,提分率90%+机构全解析随着留学申请竞争的加剧,托福成绩作为海外院校录取的核心指标之一,其备考效率与提分质量备受关注。北京作为留学教育资源聚集地,托福培训机构数量…

Why did Sanminism fail?

maybe the traditional Chinese should be Extincted. Jack London thinks Hieroglyphs should all die. So it was simplified. then it should be Chinese. it should be Asian, it should be European, it should o…

网络安全产品深度对比:Detectify与Halo Security的技术架构剖析

本文深入对比Detectify和Halo Security两款外部安全平台的技术架构,涵盖资产发现与分类、漏洞评估方法和用户体验三大核心领域,分析各自的自动化扫描引擎、API测试能力和工作流程设计差异。产品对比:Detectify vs. …

pyppeteer: 连接到已打开的chrome

一,chrome启动调试端口 $ google-chrome --remote-debugging-port=9222 --user-data-dir=/data/python/xianyu/userdataDevTools listening on ws://127.0.0.1:9222/devtools/browser/faddaa6e-98ec-444e-9710-9b7198…

深入解析:【开题答辩过程】以《重庆市社区养老服务小程序设计与实现》为例,不会开题答辩的可以进来看看

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …