jdjwzx233的博客

如无特别声明,该博客文章均为 jdjwzx233 原创,转载请遵循署名 - 非商业性使用 4.0 国际(CC BY-NC-SA)协议,即转载请注明文章来源。 如发现用户发布违规内容或评论,管理员将封禁其 IP 地址!(所有 jdjwzx233 的站点将不可访问。如果有误封,请联系 admin@jdjwzx233.cn 进行申诉) 本博客使用 hexo 进行搭建,采用 shoka 主题。 本博客属于非商业性质的博客。 如需联系 jdjwzx233,请点击这里,或通过添加好友的方式联系 jdjwzx233-bot(QQ: 1438148243)。在进入 QQ 后,向 jdjwzx233-bot 发送指令 "!rg",即可获取 jdjwzx233 的联系方式。获取好友验证码请参考第 7 条。 如果博客文章、使用的图片等侵犯了您的版权或给您带来了损失,请联系 admin@jdjwzx233.cn。 jdjwzx233-bot 的好友验证码为:jdjwzx233blogyyds(不定时更改)。 jdjwzx233-bot 将于 2023 年二月份关闭,客服业务已经转移到 jdjwzx233-Blog 上。您现在可以通过博客右下角的咨询按钮联系 jdjwzx233-Blog 的管理员。 如果喜欢 jdjwzx233-Blog,请点击这里订阅,获取 jdjwzx233-Blog 的最新动态。 如果您访问本站,即表示您同意本站的隐私政策、Cookie 政策、服务条款和免责声明。如果您不同意相关政策和条款,请勿访问本站。您可以联系 admin@jdjwzx233.cn 删除您在本站中的一切信息(包括评论、账户、文章等)。 为了尊重和保护访客和用户的隐私权,我们提供了一种方便的方式来关闭网站跟踪器。您可以在网站底部找到相应选项,以便自主选择是否接受网站跟踪。我们鼓励您在使用我们的网站时行使您的选择权,以获得更加个性化和符合您需求的浏览体验。 本站点已启用腾讯云 CDN 加速,加速网址:www.jdjwzx233.cn 您可以使用爱发电赞助本博客的运营和开发。 赞助感谢名单:https://sponsorme.jdjwzx233.com/ 爱发电-jdjwzx233 每月5元,感谢您的赞助 广告: LightNode:拥有高质量香港 CN2 GIA 节点与原生 IP (河内、曼谷、华盛顿、柬埔寨)。充值 10 美元,最多账户获得 30 美元,10 美元可用 5 个月,相当于不要钱。(支持支付宝、银联、paypal 等支付方式)。对于想用 VPS 解锁 **「Netflix、 TikTok」** 或者其他流媒体,以及对 CN2 有需求的都可以看看。官网链接:www.lightnode.com 又拍云:又拍云有非常多的优惠:加入又拍云联盟 (网站需备案,要在网站 / 应用底部添加又拍云 LOGO 并指向官网) 后,可以获得每月 10G 储存空间和 15G 的 CDN 流量 (按年发放,以 67 元的代金卷发放到账户);新用户注册 (点我注册) 还可以直接获得 61 元的代金卷 (有效期一年)。在这些优惠的加成下,你可以零成本建站。 Ciallo~(∠・ω< )⌒★

2025/10/11
articleCard.readMore

网页自动翻译功能全攻略

# 前言 在全球化互联网生态中,网站访问者往往来自不同语言背景,语言壁垒成为信息传递的天然障碍。传统多语言方案依赖人工维护静态翻译文件,不仅更新滞后、维护成本高昂,更无法应对动态内容和用户生成数据的实时翻译需求。与此同时,许多开发者陷入两难:直接调用谷歌翻译等公共接口可能面临服务稳定性风险,而私有化部署方案又常因技术复杂度望而却步。 为突破这一困局,现代网页自动翻译技术应运而生。它不仅能实现毫秒级动态内容转化,更通过智能术语库和私有接口对接,在提升用户体验与控制翻译质量之间找到平衡点。 # 一、谷歌翻译原生集成方案 # 1. 实现原理 通过动态加载谷歌翻译的脚本( element.js ),在页面中插入翻译控件,利用 Google 的云端接口实现实时翻译。 # 2. 操作步骤 1 2 3 4 5 6 7 8 9 10 11 12 <!-- index.html 中插入脚本加载逻辑 --> <script> window.onload = function() { const script = document.createElement('script'); script.src = 'https://translate.google.com/translate_a/element.js?cb=googleTranslateElementInit'; script.onerror = () => console.error('Google 翻译加载失败,请检查网络环境'); document.head.appendChild(script); }; </script> <!-- 翻译控件容器 --> <div id="google_translate_element" style="position:fixed;bottom:20px;right:20px;z-index:999"></div> 1 2 3 4 5 6 7 8 // Vue/React 组件中初始化翻译器 function googleTranslateElementInit() { new google.translate.TranslateElement({ pageLanguage: 'zh-CN', includedLanguages: 'en,ja,ko,es', // 限制可切换语言 layout: google.translate.TranslateElement.InlineLayout.SIMPLE }, 'google_translate_element'); } 注意事项:需科学上网环境支持,频繁调用可能触发接口限制。 # 二、使用 i18n-jsautotranslate 库 1 2 3 4 5 6 7 8 // main.js 全局配置 import translate from 'i18n-jsautotranslate'; translate.listener.start(); // 监控动态文本 Vue.prototype.$translate = translate; // 组件内切换语言 this.$translate.changeLanguage('english'); this.$translate.execute(); // 强制刷新翻译 特点:轻量级集成,但需手动处理接口返回的动态内容。 # 三、使用 translate.js 实现 (此处为简略内容,详细的看最后面) 使用 GitHub 项目:translate,如果你觉得这个项目好的话,可以去给项目点个 star # 3.1 基础集成 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <!-- 引入核心库 --> <script src="https://cdn.staticfile.net/translate.js/3.12.0/translate.js"></script> <!-- 自定义语言切换按钮 --> <div class="lang-switcher"> <button onclick="translate.changeLanguage('english')">English</button> <button onclick="translate.changeLanguage('chinese_simplified')">简体中文</button> </div> <script> // 初始化配置 translate.language.setLocal('chinese_simplified'); // 设置源语言 translate.service.use('client.edge'); // 使用边缘计算翻译通道 translate.execute(); // 立即执行翻译 </script> # 3.2 核心功能详解 # (1)动态内容监控 1 2 translate.listener.start(); // 开启DOM变动监听 translate.ignore.class.push('no-translate'); // 忽略特定class 应用场景:Vue/React 等框架的动态渲染内容自动翻译。 # (2)自定义术语库 1 2 3 4 translate.term.set({ 'OpenAI': '开放人工智能', 'GPT-4': '生成式预训练模型4.0' }); 效果:强制替换指定词汇,解决机器翻译不准确问题。 # (3)私有翻译接口 1 2 3 translate.service.use('http://your-api.com/translate'); // 自定义请求头(如API密钥) translate.request.headers.set('Authorization', 'Bearer xxxxxx'); # (4)高级缓存控制 1 2 3 4 5 // 重写本地缓存策略 translate.cache.setHandler({ set: (key, value) => sessionStorage.setItem(key, value), get: (key) => sessionStorage.getItem(key) }); # 3.3 快速实现 (自动识别语语言并翻译) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <!-- 页面底部语言切换区 --> <span id="DONOTTRANSLATE"> 语言切换: <a href="javascript:translate.changeLanguage('english')">English</a> | <a href="javascript:translate.changeLanguage('japanese')">日本語</a> </span> <script> window.onload = () => { translate.selectLanguageTag.show = false; // 隐藏默认切换器 translate.ignore.id.push('DONOTTRANSLATE'); // 保护切换按钮不被翻译 translate.setAutoDiscriminateLocalLanguage(); // 自动识别用户语种 translate.listener.start(); // 监听动态内容 }; </script> # 3.4 性能优化与调试技巧 # 1. 按需翻译 1 2 3 4 // 仅翻译特定区块 translate.execute({ selector: '#main-content, .article-text' }); # 2. 网络优化 1 2 // 启用CDN加速 translate.service.use('client.cdn'); # 3. 错误捕获 1 2 3 4 translate.on('error', (err) => { console.error('翻译失败:', err.message); fallbackToStaticText(); // 切换备用方案 }); # 五、扩展阅读与参考资料 # translate.js 补充教程 (详细) # 第一章:基础集成与配置 # 1.1 环境搭建与快速启动 1 2 3 4 5 6 7 8 9 10 11 12 <!-- 标准集成模式 --> <script src="https://cdn.staticfile.net/translate.js/3.12.0/translate.js"></script> <script> // 设置本地语种为简体中文(影响自动识别逻辑) translate.language.setLocal('chinese_simplified'); // 使用边缘计算翻译通道(默认服务节点) translate.service.use('client.edge'); // 初始化后立即执行首次翻译 translate.execute(); </script> 技术细节: 使用 setLocal() 方法声明源语言类型,支持 87 种 ISO 标准语言代码 client.edge 模式采用分布式 CDN 节点,平均响应时间 <200ms 自动执行 DOM 扫描,遍历所有文本节点并建立翻译索引 # 1.2 服务通道配置 通道类型 代码示例 适用场景 并发限制 公有云基础版 translate.service.use('client.basic') 个人博客 / 小型站点 100 次 / 分钟 边缘计算加速版 translate.service.use('client.edge') 企业官网 / 中等流量 无限制 私有化部署版 translate.service.use('http://your-api') 金融 / 医疗等敏感行业 自定义 企业专线版 translate.service.use('enterprise.pro') 跨国业务 / 高 SLA 要求 无限制 注意事项: 私有化部署需配置 translate.request.headers.set('X-Auth-Key', 'xxx') 认证 企业版需联系官方开通,支持双向 TLS 加密传输 # 第二章:核心功能开发 # 2.1 动态内容处理 1 2 3 4 5 6 7 8 9 10 11 12 13 // 开启实时监控(适用于 Vue/React) translate.listener.start({ interval: 300, // DOM 检查间隔(ms) depth: 5 // 监控嵌套层级 }); // 自定义忽略规则 translate.ignore .id.push('ad-container') // 忽略指定 ID .class.push('no-translate') // 忽略指定 class .tag.push('code') // 忽略代码块 .text.push('OpenAI') // 保留专有名词 .attr.add('data-translate', 'false'); // 自定义属性标记 优化策略: 使用 MutationObserver 实现增量更新,避免全量扫描 通过 translate.refresh(element) 手动刷新指定区域 # 2.2 术语库管理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // 静态术语配置 translate.term.set({ 'GPT-4': '生成式预训练模型4.0', 'CEO': '首席执行官' }); // 动态加载术语库 fetch('/dict/custom.json') .then(res => res.json()) .then(data => translate.term.merge(data)); // 术语优先级配置 translate.term.priority = { user: 100, // 用户自定义术语 system: 50 // 系统预设术语 }; 高级特性: 支持正则表达式匹配: translate.term.set({ '/d{4}-d{2}/': '日期格式' }) 提供术语版本控制接口 translate.term.version = 'v2.1' # 2.3 混合翻译模式 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 // 启用本地缓存翻译 translate.cache.enable({ ttl: 86400, // 缓存有效期(秒) strategy: 'stale' // 过期后仍使用旧数据 }); // 配置离线词库 translate.offline.load({ 'hello': { 'zh-CN': '你好', 'ja-JP': 'こんにちは' } }); // 优先级策略设置 translate.strategy.set('hybrid', { order: ['cache', 'offline', 'api'] }); 性能对比: 模式 首屏加载 二次加载 网络依赖 纯 API 1200ms 800ms 是 混合模式 1500ms 200ms 部分 纯离线 300ms 50ms 否 # 第三章:企业级部署方案 # 3.1 私有化架构设计 1 2 3 4 5 6 7 8 9 10 11 12 # 部署翻译引擎 docker run -d \ -p 8080:80 \ -v /data/translate:/app/data \ translate/service:enterprise # 配置负载均衡 upstream translate_cluster { server 10.0.0.1:8080 weight=5; server 10.0.0.2:8080 weight=3; server 10.0.0.3:8080 weight=2; } 安全方案: 传输层:TLS 1.3 + 双向证书认证 数据层:AES-256-GCM 端到端加密 审计层:全量操作日志记录 # 3.2 高可用性配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 // 客户端故障转移策略 translate.service.fallback = [ 'https://node1.your-domain.com', 'https://node2.your-domain.com', 'client.edge' // 公有云兜底 ]; // 服务端健康检查 setInterval(() => { fetch('/health') .then(res => { if (!res.ok) Kubernetes.restartPod('translate-service'); }); }, 60000); SLA 指标: 指标 目标值 监控方式 可用性 99.99% Prometheus 平均延迟 <300ms Elastic APM 错误率 <0.1% Sentry 并发容量 10,000/s LoadRunner # 第四章:高级开发技巧 # 4.1 自定义渲染引擎 1 2 3 4 5 6 7 8 9 class CustomRenderer extends translate.Renderer { onTextNode(node, translation) { if (node.parentNode.tagName === 'H1') { return `<span class="highlight">${translation}</span>`; } return translation; } } translate.renderer.use(new CustomRenderer()); # 4.2 翻译流水线扩展 1 2 3 4 5 6 7 8 9 // 添加预处理插件 translate.pipeline.before('translate', (text, context) => { return text.replace(/\b\d{4}\b/g, '<year>'); }); // 添加后处理插件 translate.pipeline.after('translate', (text, context) => { return text.replace(/<year>/g, new Date().getFullYear()); }); # 4.3 多模态翻译 1 2 3 4 5 6 7 8 9 10 11 12 13 // 图片OCR翻译 translate.image.translator = async (imgElement) => { const text = await OCR.detect(imgElement.src); return translate.execute(text); }; // 视频字幕处理 translate.video.handle = (videoElement) => { const tracks = videoElement.textTracks; tracks.forEach(track => { translate.subtitle.process(track); }); }; # 第五章:调试与优化 # 5.1 性能分析工具 1 2 3 4 5 6 7 8 9 10 // 开启性能监控 translate.monitor.enable({ metrics: ['dom-parse', 'network', 'render'], sampling: 0.1 // 10%采样率 }); // 自定义性能指标 translate.monitor.define('custom-metric', () => { return performance.now() - window.translateStart; }); # 5.2 内存优化方案 1 2 3 4 5 6 7 8 9 10 11 // 分块加载策略 translate.chunk.set({ size: 500, // 每块500字符 parallel: 3 // 最大并发数 }); // DOM 回收机制 translate.garbageCollector.run({ interval: 30000, policy: 'aggressive' }); # 结语 您还可以可通过 官方演示站点 体验完整功能,更多企业级方案请参考 Gitee 仓库。 # 参考资料 translate.js 官方文档: http://translate.zvo.cn/43086.html 谷歌翻译私有化部署指南: https://cloud.google.com/translate 多语言 SEO 优化策略: https://developers.google.com/search/docs/advanced/crawling/managing-multi-regional-sites 提示:访问 本站: jdjwzx233.cn 点击页面底部语言切换按钮,可实时体验 translate.js 的实际效果。 # 结尾 非常感谢你能看到这里,如有什么问题欢迎在评论区中提出!如果可以的话,请订阅我的网站:https://jdjwzx233.cn/Subscribe https://jdjwzx233.cn/support。

2025/5/1
articleCard.readMore

使用Netlify搭建反向代理

1. 免责声明 在撰写本文时,我旨在为技术爱好者提供有关如何使用 Netlify 搭建反向代理的技术指导和示例。请注意,本文中的信息和建议仅供参考,具体实施可能会因实际情况而有所不同。使用本文提供的方法和步骤时,请确保遵循当地法律法规,并充分考虑网络安全和数据保护的要求。 本文作者和发布平台对因使用本文内容而导致的任何直接或间接损失、损害或法律责任不承担任何责任。建议在实施任何技术方案之前,进行充分的测试和风险评估,并寻求专业意见,以确保符合适用的法律和行业标准。 2. 合法用途声明 请遵守相关法律法规,包括但不限于《中华人民共和国网络安全法》和《互联网信息服务管理办法》。请确保在使用 Netlify 或其他服务时: 合法合规:确保所搭建的反向代理不用于违反法律法规的活动,包括但不限于绕过审查、非法数据传输、或其他违法用途。 尊重版权和隐私:遵守版权法律,确保所代理的内容不侵犯第三方的知识产权。同时,保障用户隐私,遵循数据保护的相关要求。 网络安全:采取必要的安全措施,防止反向代理服务被用于恶意目的,保障系统和用户数据的安全。 信息透明:确保提供的服务信息清晰透明,用户可以明确知晓反向代理的用途和可能的风险。 # 前言 / 摘要 在当今互联网环境下,尤其是部分国外和国内网站常常由于 DNS 污染和其他原因而无法正常访问,这成为了许多用户的一大困扰。此外,有些网站虽然仅能通过 IP 地址进行访问,却无法绑定自定义域名,这同样限制了其灵活性和可用性。为了解决这些问题,搭建一个反向代理服务器成为了一个有效的解决方案。反向代理不仅可以帮助用户绕过 DNS 污染的问题,还能让我们以自定义的域名来访问那些仅能通过 IP 地址访问的网站。 在本篇文章中,我们将利用 Netlify 这一强大而易于使用的工具来搭建反向代理。Netlify 的强大之处在于其简洁的配置过程和强大的功能,使得即使是对技术不太熟悉的用户也能轻松上手。要完成这项任务,你只需具备两个基本条件:一个 Netlify 账号和一个 GitHub 账号。接下来,我们将详细介绍如何通过这两个账户配置反向代理。 # 正文 温馨提示 # 第一步 准备用于搭建反代的环境 # 1. 创建储存库 创建一个用于存放 Netlify 配置文件的 GitHub 储存库 如图: # 2. 创建配置文件 新建名为 netlify.toml 的配置文件 如图: 文件内容为: 1 2 3 4 [[redirects]] from = "/*" to = "https://github.com/:splat" status = 200 # 选择性内容 再新建一个储存库,用于搭建管理后台 (选) 如图: # 储存库中包含的文件 (选): 1 2 3 4 5 6 7 8 9 │ index.html │ package.json │ README.md │ └─netlify   └─functions     auth-callback.js     check-auth.js     update-redirect.js index.html:应用的主要前端页面,包含用户登录和配置反向代理的表单。(选) 温馨提示 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>反代配置</title> <style> body { font-family: Arial, sans-serif; background: linear-gradient(to bottom, #87CEFA, #FFFFFF); margin: 0; padding: 0; display: flex; justify-content: center; align-items: center; height: 100vh; overflow-x: hidden; } .container { text-align: center; width: 90%; max-width: 500px; } h1 { color: #333; margin-bottom: 20px; font-size: 1.8em; } form { background: #f9f9f9; border-radius: 15px; padding: 20px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); transition: transform 0.3s ease-in-out; } form:hover { transform: scale(1.02); } label { font-size: 1.2em; display: block; margin-bottom: 10px; color: #555; } input[type="url"] { width: calc(100% - 22px); padding: 10px; border-radius: 8px; border: 1px solid #ddd; margin-bottom: 20px; font-size: 1em; box-sizing: border-box; } button { background-color: #87CEFA; color: white; border: none; padding: 10px 20px; border-radius: 8px; cursor: pointer; font-size: 1.1em; transition: background-color 0.3s ease-in-out; } button:hover { background-color: #00BFFF; } #message { font-size: 1.2em; color: #333; margin-top: 20px; } .error-container, .success-container { display: none; background: #f0f8ff; border: 1px solid #d4edda; border-radius: 8px; padding: 20px; margin-top: 20px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); text-align: center; } .error-container { border-color: #f5c6cb; background: #f8d7da; color: #721c24; } .success-container { border-color: #c3e6cb; background: #d4edda; color: #155724; } .error-container p, .success-container p { margin: 0; } .success-container button { margin-top: 10px; background-color: #4CAF50; border: none; } .success-container button:hover { background-color: #45a049; } .tooltip { position: relative; display: inline-block; cursor: pointer; } .tooltip .tooltiptext { visibility: hidden; width: 200px; background-color: #333; color: #fff; text-align: center; border-radius: 6px; padding: 5px 10px; position: absolute; z-index: 1; bottom: 125%; left: 50%; margin-left: -100px; opacity: 0; transition: opacity 0.3s; } .tooltip:hover .tooltiptext { visibility: visible; opacity: 1; } #loginContainer { display: none; } </style> </head> <body> <div class="container"> <h1>反代配置器</h1> <div id="loginContainer"> <p>请登录以访问此页面。</p> <button id="loginButton">使用 GitHub 登录</button> </div> <form id="redirectForm" style="display: none;"> <div class="tooltip"> <label for="website">请输入要反代到的网址:</label> <span class="tooltiptext">请输入完整的 URL 地址,例如 https://example.com</span> </div> <input type="url" id="website" name="website" required> <button type="submit">提交</button> </form> <div id="errorMessage" class="error-container"> <p id="errorStatusMessage"></p> </div> <div id="successMessage" class="success-container"> <p id="successStatusMessage"></p> <button id="redirectButton" style="display: none;">前往反代网站</button> </div> </div> <script> async function checkAuthentication() { const response = await fetch('/.netlify/functions/check-auth'); const result = await response.json(); if (result.authenticated) { document.getElementById('loginContainer').style.display = 'none'; document.getElementById('redirectForm').style.display = 'block'; } else { document.getElementById('loginContainer').style.display = 'block'; document.getElementById('redirectForm').style.display = 'none'; } } document.getElementById('loginButton').addEventListener('click', () => { window.location.href = `https://github.com/login/oauth/authorize?client_id=【这里填你的GitHub clientid】&redirect_uri=${encodeURIComponent(window.location.origin + '/.netlify/functions/auth-callback')}`; }); document.getElementById('redirectForm').addEventListener('submit', async (event) => { event.preventDefault(); const website = document.getElementById('website').value; const urlPattern = /^https?:\/\/[^\/]+$/; const errorMessageElement = document.getElementById('errorStatusMessage'); const successMessageElement = document.getElementById('successStatusMessage'); const errorContainer = document.getElementById('errorMessage'); const successContainer = document.getElementById('successMessage'); const redirectButton = document.getElementById('redirectButton'); if (!urlPattern.test(website)) { const suggestion = website.replace(/\/+$/, ''); errorMessageElement.innerText = `输入的 URL 格式不正确。请确保网址以 'https://example.com' 形式输入。你可能的正确输入是:${suggestion}`; errorContainer.style.display = 'block'; successContainer.style.display = 'none'; return; } const response = await fetch('/.netlify/functions/update-redirect', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ website }) }); const result = await response.json(); if (result.message === 'Redirect updated successfully!') { successMessageElement.innerText = '反代配置成功!请等待服务器更新,预计1分钟。'; successContainer.style.display = 'block'; errorContainer.style.display = 'none'; redirectButton.style.display = 'inline-block'; redirectButton.addEventListener('click', () => { window.location.href = '【这里填你的反代网站,不是后台】'; }); } else { errorMessageElement.innerText = `配置失败:${result.message}`; errorContainer.style.display = 'block'; successContainer.style.display = 'none'; } }); // Initialize the authentication check checkAuthentication(); </script> </body> </html> /netlify/functions/auth-callback.js:处理 GitHub OAuth 回调的函数,设置用户的登录状态。(选) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 exports.handler = async function(event, context) { const clientId = process.env.GITHUB_CLIENT_ID; const clientSecret = process.env.GITHUB_CLIENT_SECRET; const allowedUsers = process.env.ALLOWED_USERS.split(','); const jwtSecret = process.env.JWT_SECRET; const code = event.queryStringParameters.code; if (!code) { return { statusCode: 400, body: JSON.stringify({ message: 'Missing code parameter' }) }; } try { const fetch = (await import('node-fetch')).default; const jwt = (await import('jsonwebtoken')).default; const response = await fetch(`https://github.com/login/oauth/access_token`, { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, body: JSON.stringify({ client_id: clientId, client_secret: clientSecret, code: code }) }); const data = await response.json(); if (data.error) { throw new Error(data.error_description); } const userResponse = await fetch('https://api.github.com/user', { headers: { Authorization: `token ${data.access_token}` } }); const userInfo = await userResponse.json(); if (allowedUsers.includes(userInfo.login)) { const token = jwt.sign({ username: userInfo.login }, jwtSecret, { expiresIn: '1h' }); return { statusCode: 302, headers: { 'Set-Cookie': `token=${token}; Path=/; HttpOnly`, 'Location': '/' }, body: '' }; } else { return { statusCode: 403, body: JSON.stringify({ message: 'Unauthorized' }) }; } } catch (error) { return { statusCode: 500, body: `Error: ${error.message}` }; } }; /netlify/functions/check-auth.js:检查用户是否已登录的函数。(选) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 exports.handler = async function(event, context) { const jwtSecret = process.env.JWT_SECRET; const cookieHeader = event.headers.cookie || ''; const cookies = Object.fromEntries(cookieHeader.split('; ').map(cookie => cookie.split('='))); const token = cookies.token; try { const jwt = (await import('jsonwebtoken')).default; jwt.verify(token, jwtSecret); return { statusCode: 200, body: JSON.stringify({ authenticated: true }) }; } catch (err) { return { statusCode: 403, body: JSON.stringify({ authenticated: false }) }; } }; /netlify/functions/update-redirect.js:处理反向代理配置的函数。(选) 温馨提示 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 exports.handler const jwtSecret = process.env.JWT_SECRET; const allowedUsers = process.env.ALLOWED_USERS.split(','); const cookieHeader = event.headers.cookie || ''; const cookies = Object.fromEntries(cookieHeader.split('; ').map(cookie => cookie.split('='))); const token = cookies.token; let decodedToken; try { const jwt = (await import('jsonwebtoken')).default; decodedToken = jwt.verify(token, jwtSecret); } catch (err) { return { statusCode: 403, body: JSON.stringify({ message: 'Unauthorized' }) }; } if (!allowedUsers.includes(decodedToken.username)) { return { statusCode: 403, body: JSON.stringify({ message: 'Unauthorized' }) }; } const { Octokit } = await import('@octokit/rest'); const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN }); const { website } = JSON.parse(event.body); if (!website) { return { statusCode: 400, body: JSON.stringify({ message: 'No website provided' }) }; } try { const fetch = (await import('node-fetch')).default; const { data: fileData } = await octokit.repos.getContent({ owner: '【这里填入你的GitHub用户名】', repo: '【用于存放Netlify配置文件的GitHub储存库名称】', path: 'netlify.toml' }); const content = Buffer.from(fileData.content, 'base64').toString(); const newContent = content.replace(/to\s*=\s*"[^"]+"/, `to = "${website}/:splat"`); await octokit.repos.createOrUpdateFileContents({ owner: '【这里填入你的GitHub用户名】', repo: '【用于存放Netlify配置文件的GitHub储存库名称】', path: 'netlify.toml', message: 'Update redirect URL', content: Buffer.from(newContent).toString('base64'), sha: fileData.sha }); return { statusCode: 200, body: JSON.stringify({ message: 'Redirect updated successfully!' }) }; } catch (error) { console.error(error); return { statusCode: 500, body: JSON.stringify({ message: 'Failed to update redirect' }) }; } }; package.json:存放依赖的文件。(选) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 { "name": "Rcs, "version": "1.0.0", "description": "A reverse proxy configurator with GitHub authentication deployed on Netlify.", "main": "index.js", "scripts": { "start": "netlify dev", "build": "netlify build" }, "dependencies": { "@octokit/rest": "^19.0.7", "jsonwebtoken": "^9.0.2", "node-fetch": "^3.3.2" }, "devDependencies": { "netlify-cli": "^15.0.0" }, "engines": { "node": ">=16.x" }, "author": "j23", "license": "MIT" } # 第二步 配置 Netlify # 1. 创建一个站点 如图: 选择你的用于存放 Netlify 配置文件的 GitHub 储存库 # 2. 配置自定义域名 自此所有基本操作已经完成,如果不需要配置后台,你只需要修改 Netlify 配置文件中的链接,就可以实现更换需要代理的网站。 修改内容如下 (注意!,网址格式必须为 https://example.com/,不能删去 https:// 也不能删去最后的 /): 1 2 3 4 [[redirects]] from = "/*" to = "【修改这里】:splat" status = 200 # 选择性内容 # 一.GitHub 登录 使用 GitHub 进行 OAuth 登录,确保只有授权用户可以访问配置功能。 # 第一步: 打开下面网址,并填好配置 https://github.com/settings/applications/new # 第二步: 获取 Client ID,并生成 Client secrets,后面要用 警告! # 二。配置用于修改储存库的密钥 打开下面的网址 https://github.com/settings/tokens 填入相关内容,选择不过期,勾选储存库 获取到密钥 警告! # 三。配置 Netlify # 第一步:创建站点 如图: 选择你的后台储存库 填入环境变量 1 2 3 4 5 ALLOWED_USERS:你授权使用后台的GitHub用户名,用半角逗号隔开,如果只有一个用户,则无需逗号。如:用户名1,用户名2 GITHUB_CLIENT_ID:你的CLIENT_ID GITHUB_CLIENT_SECRET:你的CLIENT_SECRET GITHUB_TOKEN:你的GitHub账号密钥 JWT_SECRET:一个随机的不限位数的字符串,如wfhehfihwjdwefnabwaieu72dub3uigfvqty2UGQWADIWGADIY3UGF378 # 第二步。配置自定义域名 # 结尾 非常感谢你能看到这里,如有什么问题欢迎在评论区中提出!如果可以的话,请订阅我的网站:https://jdjwzx233.cn/Subscribe https://jdjwzx233.cn/support。

2024/9/17
articleCard.readMore

搭建jsdelivr镜像(又拍云/nginx/cfwokers/Deno)

# 前言 jsDelivr —— 一个免费、快速、可靠的为 JS 和开源项目服务的 CDN。但是由于国内访问速度慢,加之 jsDelivr 备案被吊销和 DNS 污染常出现,国内使用了 jsDelivr 的站点常常出现访问速度慢的问题。 同时,本文也适用于其他网站的镜像搭建。 # 方法一:使用又拍云搭建 # 优点: 又拍云是国内知名企业级云服务商,其服务极速、稳定、简单易用,用来搭建镜像站是十分合适的。又拍云有非常多的优惠:加入又拍云联盟 (网站需备案,要在网站 / 应用底部添加又拍云 LOGO 并指向官网) 后,可以获得每月 10G 储存空间和 15G 的 CDN 流量 (按年发放,以 67 元的代金卷发放到账户);新用户注册 (点我注册) 还可以直接获得 61 元的代金卷 (有效期一年)。在这些优惠的加成下,你可以零成本搭建一个镜像站。 2. 加速效果明显 (如图) 加速前: 加速后: # 缺点: 需要备案!!! # 推荐指数:⭐⭐⭐⭐⭐ # 搭建方法: # 第一步: 创建又拍云账户 (点我注册) # 第二步: 进入控制台的 CDN 管理界面 (https://console.upyun.com/services/cdn/), 并创建服务,然后配置服务 (具体参数如下)。 服务名称:唯一标识服务,例如:image-upyun-com,一个服务下面可以绑定多个自有域名。 注意事项 加速域名:填写此次需要配置的加速域名。 注意事项 加速域名需要进行域名所有权验证,验证通过后方能添加成功。 应用场景:这里选择全站加速 回源协议:选协议跟随。 源站证书校验:切记!!不要打开 (实测开了以后不能用)!!! 线路配置:源站地址填 cdn.jsdelivr.net , 端口号不要动。 # 第三步 服务创建成功后,操作界面会提示 CDN 加速服务创建成功,并会自动跳转到该服务的【功能配置】界面 在功能配置界面,有域名管理、回源管理、缓存配置、性能优化、HTTPS、访问控制、图片处理等功能配置模块,在【域名管理】模块下,可以针对该服务绑定多个自有域名,请耐心等待域名配置(约 10 分钟),查看域名对应的状态是否为[正常] 可查看 CDN 平台为您分配的 CNAME 地址,此时需要去域名 DNS 解析商处,为该域名添加一条 CNAME 记录,待 CNAME 配置生效之后,方可使用 CDN 服务。 # 第四步 (非必要,但是可以提升体验) 配置 HTTPS: 点击 [HTTPS], 点击 "HTTPS 配置" 右边的管理 (如图) 然后你可以选择添加自有证书或直接使用又拍云注册证书 (点我前往证书管理)。添加完后,打开 [HTTPS 访问],不建议勾选 [强制 HTTPS 访问]。 建议打开智能压缩和页面压缩 (如图) 建议配置缓存、浏览器缓存和分段缓存 (如图) 在 [访问控制] 中,打开 Referer 防盗链、WAF 保护、HTTP 请求体大小限制、IP 访问限制 (如图) 此配置仅作参考,请根据实际情况进行配置! 你还可以配置 [边缘规则],来实现一些特殊效果。(这里不做演示) # 方法二:使用 Cloudflare workers 搭建 # 优点: 简单,步骤少,加速范围广 无需备案,加速效果较好 (如图) 加速后: 无费用,每天有免费额度 (每天免费 100000 个请求) # 缺点: 部分地区访问较慢 免费额度较少,对于访问量大的站点可能不够 需要有一个挂在 cloudflare 的域名 # 推荐指数:⭐⭐⭐⭐ # 搭建方法 # 第一步 在 Cloudflare 管理面板的 [Workers 和 Pages] 栏 ->[概述]->[创建应用程序]->[创建 Worker](如图) 随便填一个名称,点击 [部署](如图) # 第二步 在创建完成的页面点击 [编辑代码](如图) 将以下代码直接粘贴进代码框: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 'use strict' /** * static files (404.html, sw.js, conf.js) */ const ASSET_URL = 'https://cdn.jsdelivr.net' const JS_VER = 10 const MAX_RETRY = 1 /** @type {RequestInit} */ const PREFLIGHT_INIT = { status: 204, headers: new Headers({ 'access-control-allow-origin': '*', 'access-control-allow-methods': 'GET,POST,PUT,PATCH,TRACE,DELETE,HEAD,OPTIONS', 'access-control-max-age': '1728000', }), } /** * @param {any} body * @param {number} status * @param {Object<string, string>} headers */ function makeRes(body, status = 200, headers = {}) { headers['--ver'] = JS_VER headers['access-control-allow-origin'] = '*' return new Response(body, {status, headers}) } /** * @param {string} urlStr */ function newUrl(urlStr) { try { return new URL(urlStr) } catch (err) { return null } } addEventListener('fetch', e => { const ret = fetchHandler(e) .catch(err => makeRes('cfworker error:\n' + err.stack, 502)) e.respondWith(ret) }) /** * @param {FetchEvent} e */ async function fetchHandler(e) { const req = e.request const urlStr = req.url const urlObj = new URL(urlStr) const path = urlObj.href.substr(urlObj.origin.length) if (urlObj.protocol === 'http:') { urlObj.protocol = 'https:' return makeRes('', 301, { 'strict-transport-security': 'max-age=99999999; includeSubDomains; preload', 'location': urlObj.href, }) } if (path.startsWith('/http/')) { return httpHandler(req, path.substr(6)) } switch (path) { case '/http': return makeRes('请更新 cfworker 到最新版本!') case '/ws': return makeRes('not support', 400) case '/works': return makeRes('it works') default: // static files return fetch(ASSET_URL + path) } } /** * @param {Request} req * @param {string} pathname */ function httpHandler(req, pathname) { const reqHdrRaw = req.headers if (reqHdrRaw.has('x-jsproxy')) { return Response.error() } // preflight if (req.method === 'OPTIONS' && reqHdrRaw.has('access-control-request-headers') ) { return new Response(null, PREFLIGHT_INIT) } let acehOld = false let rawSvr = '' let rawLen = '' let rawEtag = '' const reqHdrNew = new Headers(reqHdrRaw) reqHdrNew.set('x-jsproxy', '1') // 此处逻辑和 http-dec-req-hdr.lua 大致相同 // https://github.com/EtherDream/jsproxy/blob/master/lua/http-dec-req-hdr.lua const refer = reqHdrNew.get('referer') const query = refer.substr(refer.indexOf('?') + 1) if (!query) { return makeRes('missing params', 403) } const param = new URLSearchParams(query) for (const [k, v] of Object.entries(param)) { if (k.substr(0, 2) === '--') { // 系统信息 switch (k.substr(2)) { case 'aceh': acehOld = true break case 'raw-info': [rawSvr, rawLen, rawEtag] = v.split('|') break } } else { // 还原 HTTP 请求头 if (v) { reqHdrNew.set(k, v) } else { reqHdrNew.delete(k) } } } if (!param.has('referer')) { reqHdrNew.delete('referer') } // cfworker 会把路径中的 `//` 合并成 `/` const urlStr = pathname.replace(/^(https?):\/+/, '$1://') const urlObj = newUrl(urlStr) if (!urlObj) { return makeRes('invalid proxy url: ' + urlStr, 403) } /** @type {RequestInit} */ const reqInit = { method: req.method, headers: reqHdrNew, redirect: 'manual', } if (req.method === 'POST') { reqInit.body = req.body } return proxy(urlObj, reqInit, acehOld, rawLen, 0) } /** * * @param {URL} urlObj * @param {RequestInit} reqInit * @param {number} retryTimes */ async function proxy(urlObj, reqInit, acehOld, rawLen, retryTimes) { const res = await fetch(urlObj.href, reqInit) const resHdrOld = res.headers const resHdrNew = new Headers(resHdrOld) let expose = '*' for (const [k, v] of resHdrOld.entries()) { if (k === 'access-control-allow-origin' || k === 'access-control-expose-headers' || k === 'location' || k === 'set-cookie' ) { const x = '--' + k resHdrNew.set(x, v) if (acehOld) { expose = expose + ',' + x } resHdrNew.delete(k) } else if (acehOld && k !== 'cache-control' && k !== 'content-language' && k !== 'content-type' && k !== 'expires' && k !== 'last-modified' && k !== 'pragma' ) { expose = expose + ',' + k } } if (acehOld) { expose = expose + ',--s' resHdrNew.set('--t', '1') } // verify if (rawLen) { const newLen = resHdrOld.get('content-length') || '' const badLen = (rawLen !== newLen) if (badLen) { if (retryTimes < MAX_RETRY) { urlObj = await parseYtVideoRedir(urlObj, newLen, res) if (urlObj) { return proxy(urlObj, reqInit, acehOld, rawLen, retryTimes + 1) } } return makeRes(res.body, 400, { '--error': `bad len: ${newLen}, except: ${rawLen}`, 'access-control-expose-headers': '--error', }) } if (retryTimes > 1) { resHdrNew.set('--retry', retryTimes) } } let status = res.status resHdrNew.set('access-control-expose-headers', expose) resHdrNew.set('access-control-allow-origin', '*') resHdrNew.set('--s', status) resHdrNew.set('--ver', JS_VER) resHdrNew.delete('content-security-policy') resHdrNew.delete('content-security-policy-report-only') resHdrNew.delete('clear-site-data') if (status === 301 || status === 302 || status === 303 || status === 307 || status === 308 ) { status = status + 10 } return new Response(res.body, { status, headers: resHdrNew, }) } /** * @param {URL} urlObj */ function isYtUrl(urlObj) { return ( urlObj.host.endsWith('.googlevideo.com') && urlObj.pathname.startsWith('/videoplayback') ) } /** * @param {URL} urlObj * @param {number} newLen * @param {Response} res */ async function parseYtVideoRedir(urlObj, newLen, res) { if (newLen > 2000) { return null } if (!isYtUrl(urlObj)) { return null } try { const data = await res.text() urlObj = new URL(data) } catch (err) { return null } if (!isYtUrl(urlObj)) { return null } return urlObj } 3. 点击 [保存并部署]。 # 第三步 回到 [概述],点击你刚才创建的项目,点击 [触发器],点击 [添加自定义域],填入一个你账户中的域名或其子域名,点击 [添加自定义域],完成搭建。 # 方法三:使用 Deno Playground 搭建 # 优点: 配置十分简单,加速范围广 无需备案,加速效果较好 (如图) 加速后: 免费额度多,每月 1000000 次请求,100G 流量 只要 DNS 解析就行,不用像 Cloudflare 一样需要修改域名 NS # 缺点: 部分地区访问较慢 没有攻击防护和其他安全功能,存在被攻击或刷流量的风险 官方自带的域名被墙,需要自备域名 # 推荐指数:⭐⭐⭐⭐⭐ # 搭建方法 # 第一步 登录后,在主页右上角点击 [New Playground] 进入代码编辑页面: # 第二步 将以下代码直接粘贴进代码框: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 const HOST = "fastly.jsdelivr.net"; Deno.serve(async (request) => { const url = new URL(request.url); url.host = HOST; const newRequest = new Request(url.toString(), { headers: request.headers, method: request.method, body: request.body, redirect: "follow", }); return await fetch(newRequest); }); 3. 点击 [Save & Deploy]。 # 第三步 回到你的项目管理页面,点击 [Settings],点击 [Domains],再点击 [Add Domain],填入一个你的域名或其子域名,点击 [Setup], 按照指示完成 DNS 解析后,点击 [Validate], 并点击自动配置证书,完成搭建。(下方有示例图) # 方法四:使用 nginx # 优点:简单 # 缺点: 加速范围不广,速度受到服务器性能和速度限制。 # 推荐指数:⭐⭐⭐ 新建一个网站,然后把下面内容覆盖到 nginx 配置文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 server { listen 80; listen 443 ssl http2; # 请更改为你的证书路径 ssl_certificate fullchain.pem; ssl_certificate_key privkey.pem; # 请更改为你的镜像域名 server_name jsd.ucbk.cn; location / { proxy_pass https://cdn.jsdelivr.net; proxy_set_header Host $proxy_host; proxy_set_header Accept-Encoding ''; proxy_ssl_server_name on; proxy_ssl_name $proxy_host; proxy_redirect / /; # Proxy Cache proxy_cache jsdelivr; proxy_cache_lock on; proxy_cache_lock_timeout 15s; proxy_cache_use_stale updating; proxy_cache_background_update on; proxy_cache_key $host$request_uri; proxy_cache_valid 200 301 302 30d; proxy_cache_valid 500 501 502 503 15s; proxy_cache_valid any 5m; # Replace Domain sub_filter_once off; sub_filter_types application/javascript application/json text/xml text/css; sub_filter '$proxy_host' '$host'; } } # 缓存路径请根据需要更改 proxy_cache_path /var/tmp/nginx/jsdelivr levels=1:2 use_temp_path=off keys_zone=jsdelivr:300m inactive=30d max_size=30g; 之后直接把网站涉及到 cdn.jsdelivr.net 都改成你自己的就可以了,如果不想改的话直接在你网站 nginx 配置中加以下内容就可以了 1 2 3 sub_filter_once off; sub_filter_types application/javascript application/json text/xml text/css; sub_filter 'cdn.jsdelivr.net' 'jsd.ucbk.cn'; # 结尾 除了上述的服务之外,还有其他同样优秀的云服务商可以用于搭建镜像,如腾讯云、阿里云等等,但都存在一个致命的问题:需要备案。希望本文提供的方法可以帮到你,你同样也可以将这个方法用在其他网站的镜像上 (只需要修改一下代码就行) 博主已经搭建了一个镜像站: mysticglow.dpdns.org 这个镜像站目前还没被墙,如有需要的,可以拿去使用,这个镜像站每个月只有 100 万次请求数和 100G 的流量,如果可以的话请自行搭建,不会或懒得搭建的可以使用本站的 (๑・ᴗ・๑)♡ 非常感谢你能看到这里,如有什么问题欢迎在评论区中提出! https://jdjwzx233.cn/support。

2023/12/24
articleCard.readMore

Edge在保留数据的情况下退出微软账户登录

现在,越来越多的人使用 Edge 浏览器来进行网络浏览,但有时候您可能需要退出微软账户登录。问题是,当您退出时,您是否会失去本地存储设备上的数据?本文将解答您的疑惑,告诉您如何在退出微软账户前保留本地数据。 # 正文 当我们无法登录账户时,如果要在 Edge 中退出微软账户登录,可能需要进入该账户的主页才能退出,否则只能使用删除该用户配置才可退出,但这会导致数据丢失,并使一些平台需要重新登录,非常的不方便。 但是,我们可以使用一些其他的方法保留数据退出登录。 在 Windows 的资源管理器中,找到你的用户数据文件夹 (正常情况都在这里)。 C:\Users\用户名\AppData\Local\Microsoft\Edge\User Data 一般来说,你的数据都存储在 Default 文件夹中,如图: 但是有时候你使用了其他用户配置,那么你的数据可能在 Profile+数字 文件夹中,这个要根据你的实际情况进行选择。 注意!以下操作可能会导致数据丢失,请提前备份好相关数据,再进行操作! 当你找到自己的数据文件夹后,你需要关闭 Edge 浏览器,注意!要到 任务管理器 中关闭,直接关闭是无效的。 关闭后,你需要备份这个文件夹,完成后,你就可以开始进行退出登录的操作了。 在你的文件夹中,找到这几个文件,如图: 以下操作可能会使你保存的密码全部丢失,请提前到设置中导出密码,再进行本操作,导入导出密码的教程放在文章结尾。 然后删除 Preferences , Login Data-journal , Login Data 这三个文件。回到浏览器后,你会发现,你的数据还在,但你的账户被退出了。 在登录你的微软账号后,你就可以导入原来的密码,完成这步后,那么恭喜你,你已经成功完成了退出微软账户保留本地数据的操作! # 转移数据 本方法同样适用于转移数据,你只需要将需要转移的用户文件夹中的内容,复制替换掉新的用户文件夹中的内容即可,在此操作之前,你需要备份被替换的用户文件夹中 Preferences , Login Data-journal , Login Data 这三个文件,在完成数据转移后,再移动回来,这样,你就完成了数据转移。 # 导出或导入密码 首先,打开 Edge://settings/passwords 或者你可以打开 设置 -> 个人资料 -> 密码 。 然后,在这个地方点击右边的三个点,如图: 选择 导出密码 ,在进行这一步时,你可能需要验证你的身份,按照步骤来就行。 最后,将你的密码保存到一个安全的地方,后面导入密码时,同样也是在此地方进行。 https://jdjwzx233.cn/support。

2023/6/25
articleCard.readMore

优秀作文分享——人间烟雨,感谢有你

烟雨迷蒙,如同人生。回首往事,最难忘却的莫过于与你相遇时的情景了吧!—— 题记 烟雨中的你是否还记得那一抹清丽的身影?这个女孩子很特别,她不像其他小姑娘一样喜欢花裙子和洋娃娃,而更爱穿着布鞋踏遍青石板路上的每一处角落。 只因为从前年幼无知的我们都曾经问过彼此:“妈妈说下雨天地面湿滑会摔跤,可以光脚走吗?” 看到大家齐刷刷摇头后便兴高采烈地脱掉了凉鞋,赤足跑进水坑或泥泞里玩耍去了…… 渐渐长大后才明白当初母亲微笑背后的苦涩心酸,也终于理解了你对我们所谓 “放养式教育” 的坚持。 多么希望能够再次见到你啊!但愿岁月静好,现世安稳。 在我眼里,你就是仙女姐姐般美好纯洁的存在,你总是用温柔细腻的手抚摸着我们受伤的心灵,告诉我们要勇敢、乐观地活出精彩。 即使偶尔发脾气,嘴巴也依旧甜甜软软的。我想你应该永远是那副没什么烦恼的模样吧,虽然我们之间隔着千山万水,但我始终觉得你离我并不遥远。尽管我们素未谋面,甚至连声音都听不真切,但仿佛冥冥之中早已注定,我们将会成为最熟悉的陌生人。 直到今日我仍深信缘分二字,命运让我们相识又让我们重逢,这种感觉实在太奇妙了。 “有朋自远方来,不亦乐乎”。古人诚不欺我,每当收到你寄来的贺卡,打开它时内心的欣喜溢于言表;翻阅它时脑海中浮现的画面似电影般闪过;合起它时鼻尖萦绕的香味久久挥散不去… 待我读懂了你的文字,品尝了你送给我的巧克力糖果,体验了你讲述的动人故事,享受了你赠予我的珍贵礼物,聆听了你传授的宝贵经验,我恍然顿悟原来我们的相遇竟是命中注定。如若不是在茫茫人海中邂逅,怎会碰撞出绚烂火花?倘若不是被你治愈了伤痛,怎会触及到柔软的内心?谢谢你,带给我的点滴暖意;谢谢你,陪伴我度过的漫长旅程;谢谢你,让我学会了坦然释怀;谢谢你,令我变得越来越优秀。 烟雨朦胧,梦境斑驳,轻捻指尖,满目芬芳。烟雨中的你,是否还记得我呢?我期盼着,下一场烟雨,我们能再次相约。

2023/1/28
articleCard.readMore

优秀作文分享——从未走远

我们从未走远,只是你没发现而已。—— 题记 一个人的心中有多少秘密?谁也无法知道,就像这世界上永远都会存在着许多令人费解之谜一样,它总是让那些充满智慧与灵感的人去猜测、探索和研究。但他们却始终得不到真正的答案。或许,每当夜深人静时,思绪便开始飞扬了吧! 于是,所谓的诗情画意,便油然而生;所谓的浪漫气息,亦由此而来…… 于是乎,古往今来,凡大家名流,皆如痴似醉地沉浸其间。对于爱情,更是乐此不疲,因为美丽的故事总能打动人心,给予读者以无限遐想空间。 “最好不相见,免得我牵念”,唐朝才子元稹写下了千古绝唱《离思》。王维用笔墨将红豆寄托出相思之苦,李商隐则借芭蕉抒怀别恨。屈原哀叹自己遭谗被疏,伍子胥含泪鞭尸,苏轼愁断肝肠,陆游悲痛欲绝。 明月照亮了黑暗,星光点缀了寂寞,文字带来了希望,纸张承载了梦想。文学作品里蕴藏着太多的内涵,需要细细揣摩,慢慢体味。 虽说花开堪折直须折,莫待无花空折枝。然而人非草木孰能无情?面对眼前的诱惑,恐怕很难把持住自己,甚至迷失方向。尤其是看惯了灯红酒绿的繁华景象,听够了莺歌燕舞的靡靡之音,享受惯了富贵荣华的锦衣玉食,接触多了形形色色的社会百态,岂能不贪恋权势金钱?试问:哪位君主甘愿做平民百姓?即使退一步讲,倘若抛弃了功名利禄,选择归隐田园,那么就必定淡泊名利吗?显然并非如此。 陶渊明辞官归隐,采菊东篱下,悠然见南山,依旧钟情于 “结庐在人境,而无车马喧” 的闲适恬淡。周敦颐厌恶官场,宁愿隐居西湖孤山,仍保持清白廉洁的节操。欧阳修贬谪滁州,饱尝艰辛困顿,仍坚守信念,矢志不渝,毫不改变初衷。… 数不胜数,比比皆是。

2023/1/28
articleCard.readMore

优秀作文分享——我,在浙里

# 第一篇: 浙江,是一片神奇美丽的土地;浙江,孕育了中华民族灿烂悠久的文明;浙江,承载着数以亿计的浙商走向世界! “三十功名尘与土,八千里路云和月”。一首《满江红》道出了岳飞壮志难酬、报国无门的悲愤心情。但他没有被挫折所压倒,反而更加坚定自己的信念 —— 收复失地,还于旧都。在历史上留下了浓墨重彩的一笔。 “位卑未敢忘忧国”。身为汉臣却始终忠心耿耿,宁死也要捍卫祖国领土完整。我想到了周恩来总理。他曾说过:“为中华崛起而读书!” 就是凭借这种强烈的爱国精神,才使得那么多仁人志士投入革命洪流,推翻黑暗统治,建立新中国! “先天下之忧而忧,后天下之乐而乐”。范仲淹从小便怀抱远大理想,立志成为像孔子一般博学多识、胸怀天下苍生的圣贤。正因此,他能够舍弃高官厚禄,毅然决然地辞职回乡,开启了著名的 “庆历新政”。虽然最终因保守势力太强而失败,但其忧国忧民的思想却永垂青史。 “居庙堂之高则忧其君,处江湖之远则忧其民”。范仲淹两度遭贬,依然关注百姓疾苦,体恤黎民百姓。在他看来,只有让老百姓安居乐业,社会才能稳定发展。 古人云:“读万卷书不如行千里路。” 不错,纸上谈兵并非真英雄。真正的勇者应当深入实践,躬亲实干。“宝剑锋从磨砺出,梅花香自苦寒来”。鲁迅先生把握住了知识分子的特点,用手中的笔作武器,唤醒麻木的国民。他写杂文,抨击封建制度的弊端,揭露军阀混战的罪恶;他写小说,描绘人民群众受压迫、受剥削的惨状,表现对劳动人民的同情和热爱。鲁迅先生用自己犀利的笔尖戳破假面具,撕去画皮,将丑陋的灵魂暴露给世人。他的每篇杂文犹如匕首,刺痛敌人的心脏。鲁迅先生毫不畏惧,奋斗一生,为后人树立了榜样。 我们生活在这样一个伟大的时代,感谢科技进步带来的方便快捷。我们拥有丰富的物质财富,可以享受电影院、健身房等娱乐设施。但是,别忘记,今日的幸福生活离不开前辈们披荆斩棘的努力拼搏。我相信,在党的领导下,我们必将创造属于我们的辉煌! # 第二篇: 浙里,我在这里。我来自浙南的温州,因为那儿有最美丽的海滨城市 —— 厦门;也许你会问:“怎么没有听说过‘东方夏威夷’呢?” 不错,它就是福建省第二大岛 —— 平潭县。而我们今天要去游览的则是被称之为 “小上海” 的浙江省会 --- 杭州。 浙江是一个人杰地灵的好地方,孕育了无数名扬四海的文化巨匠和商业奇才,还造就了灿若星辰的艺术瑰宝!古代中国有四大发明,其中三项便产生于此,可见她对世界所做出的贡献之伟大啊! 如果说北京是帝王将相聚集的地方,那么杭州绝对是富家子弟云集的场所。想当年,乾隆皇帝下江南时曾到过此处,并留下了千古佳句:“江南忆,最忆是杭州”。由此可以看出,杭州是多么令人向往与憧憬呀! “日出江花红胜火,春来江水绿如蓝”,从诗中描绘的情境可知,春季的杭州正值桃李芬芳,鸟语花香的好时节。但作者却只用了两句话概括了整个杭州的特点,让读者更加感受到了杭州的魅力与神韵。或许,每个人都有属于他(她)心目中的杭州吧! 杭州西湖景色秀丽、山清水秀,素有 “人间天堂” 的美誉。尤其是湖中央的三座小岛 - - 小瀛洲、湖心亭和阮公墩,各具风姿。 小瀛洲面积较大,岛上遍植花木,环境幽静。湖心亭是西湖中赏荷观鱼的最佳处,岛上建筑精巧别致,有水中仙子的雅号。阮公墩虽然面积比前两个小岛略小些,但却十分别致,登高远眺,西湖全景尽收眼底…… 傍晚,夕阳斜照在西湖上,映着波光粼粼的湖面,闪烁着金光,仿佛给湖面铺上了一层碎金似的,煞是耀眼夺目。微风吹拂着柳树,使它轻轻摇摆起来,像是姑娘们甩动长发跳舞一般,婀娜多姿,楚楚动人。夜幕降临后,月亮升空,皎洁的月光倾泻而下,洒落在湖面上,泛起阵阵银白色的涟漪,宛如仙女散花,又犹如牛郎织女隔河相望,真是妙趣横生!倘若遇到皓月当空,繁星满天的夜晚,坐在船头仰望苍穹,定能领悟到苏轼《水调歌头》中所写道的 “欲把西湖比西子,淡妆浓抹总相宜” 的意蕴吧!

2023/1/26
articleCard.readMore

将ChatGPT部署到网站上

ChatGPT 是一个用于自然语言对话的预训练语言模型。要将 ChatGPT 部署到网站上,你需要执行以下步骤: 下载 ChatGPT 模型:你可以从 Hugging Face 的 Transformers 库中下载 ChatGPT 模型。 使用 Python 的 Flask 库创建一个 Web 应用程序。Flask 是一种轻量级的 Web 应用框架,可以让你快速构建 Web 应用程序。 在 Web 应用中加载 ChatGPT 模型:在 Web 应用程序中,你可以使用 Transformers 库中的 AutoModelWithLMHead 类加载 ChatGPT 模型。 创建一个 HTML 表单,允许用户输入对话文本。 使用 ChatGPT 模型对用户输入的文本进行响应:当用户提交表单时,你可以使用 ChatGPT 模型的 generate 方法生成响应文本。 以下是一个简单的例子,展示了如何使用 Flask 和 ChatGPT 构建一个简单的 Web 应用程序: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 from flask import Flask, render_template, request from transformers import AutoModelWithLMHead, AutoTokenizer app = Flask(__name__) # 加载ChatGPT模型 model = AutoModelWithLMHead.from_pretrained("microsoft/DialoGPT-small") tokenizer = AutoTokenizer.from_pretrained("microsoft/DialoGPT-small") @app.route("/", methods=["GET", "POST"]) def index(): if request.method == "POST": # 获取用户输入的文本 input_text = request.form["input_text"] # 使用ChatGPT模型生成响应文本 prompt = (input_text, "") response = model.generate(prompt, max_length=1024, do_sample=True, temperature=0.7) response_text = tokenizer.decode(response[0], skip_special_tokens=True) return render_template("index.html", response_text=response_text) else: return render_template("index.html") if __name__ == "__main__": app.run() 在这段代码中,我们使用了 Flask 的 render_template 函数来渲染一个 HTML 模板,并将响应文本传递给模板。我们还使用了 Transformers 库中的 AutoTokenizer 类来将响应文本解码为可读的文本。 下面是一个简单的 HTML 模板,你可以使用它来显示用户输入和 ChatGPT 响应: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <html> <head> <title>ChatGPT Demo</title> </head> <body> <form method="POST"> <label>输入文本:</label> <input type="text" name="input_text" placeholder="输入文本" /> <button type="submit">发送</button> </form> {% if response_text %} <p>响应文本:{{ response_text }}</p> {% endif %} </body> </html> 在这个 HTML 模板中,我们创建了一个表单,允许用户输入对话文本。当用户提交表单时,Web 应用程序会使用 ChatGPT 模型生成响应文本,并使用 Flask 的 render_template 函数将响应文本传递给 HTML 模板。 要运行这个 Web 应用程序,你需要安装 Flask 和 Transformers 库,然后运行代码: 1 2 pip install flask transformers python app.py 然后,你就可以在浏览器中访问 http://localhost:5000/ 来使用这个 Web 应用程序了。 要在上述代码的基础上创建一个更美观的界面,你可以使用 HTML、CSS 和 JavaScript 来设计界面,并使用 AJAX 技术在用户输入文本后异步获取 ChatGPT 响应。 下面是一个示例代码,展示了如何使用这些技术创建一个类似聊天系统的界面: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 <html> <head> <title>ChatGPT Demo</title> <!-- 引入Bootstrap框架 --> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous"> </head> <body> <!-- 创建聊天窗口 --> <div class="container mt-5"> <div class="card"> <div class="card-header"> 聊天窗口 </div> <div class="card-body p-0" id="messages"> <!-- 显示聊天记录 --> <div class="row mb-2"> <div class="col-md-2"></div> <div class="col-md-10 text-right"> 你好,我是ChatGPT,有什么想聊的? </div> </div> </div> <!-- 创建输入框 --> <div class="card-footer"> <form> <div class="form-group"> <input type="text" class="form-control" id="input_text" placeholder="输入文本"> </div> <button type="submit" class="btn btn-primary" id="send_button">发送</button> </form> </div> </div> </div> <!-- 引入jQuery库 --> <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script> <!-- 设置AJAX请求 --> <script> $(function() { $("form").submit(function(event) { event.preventDefault(); // 获取用户输入的文本 var input_text = $("#input_text").val(); // 将文本添加到聊天记录中 $("#messages").append( '<div class="row mb-2"><div class="col-md-2"></div><div class="col-md-10">' + input_text + '</div></div>' ); // 发送AJAX请求 $.ajax({ type: "POST", url: "/chat", data: { "input_text": input_text }, success: function(response) { // 将GPT的回复添加到聊天记录中 $("#messages").append( '<div class="row mb-2"><div class="col-md-10 text-left">' + response + '</div><div class="col-md-2"></div></div>' ); } }); }); }); </script> </body> </html> 上面的代码是一个基于 HTML 和 jQuery 的聊天系统模板,使用了 Bootstrap 框架进行布局。 HTML 部分: 页面中包含一个聊天窗口,其中有一个卡片(card),卡片中包含聊天记录(card-body)和输入框(card-footer)。 聊天记录中默认显示一条消息:“你好,我是 ChatGPT,有什么想聊的?” 输入框中包含一个文本输入框(input)和一个发送按钮(button)。 jQuery 部分: 页面加载完成后,通过 jQuery 监听表单提交事件(submit)。当表单提交时,jQuery 会触发一个回调函数,这个回调函数中的代码会被执行。 当用户在输入框中输入文本并点击发送按钮时,表单提交事件(submit)被触发。 在表单提交事件的回调函数中,首先使用 event.preventDefault() 阻止默认的表单提交行为。 然后使用 $("#input_text").val() 获取用户输入的文本。 接着使用 $("#messages").append() 将文本添加到聊天记录中。 最后,使用 jQuery 的 AJAX 功能发送一个 POST 请求到服务器,将用户输入的文本作为请求参数。 当服务器返回响应时,将服务器返回的内容添加到聊天记录中。 最后,清空文本输入框,准备下一次聊天。 整个流程如下: 用户在文本输入框中输入文本,点击发送按钮。 jQuery 监听到表单提交事件,阻止默认的表单提交行为。 获取用户输入的文本。 将文本添加到聊天记录中。 发送 AJAX 请求,将用户输入的文本作为请求参数。 服务器返回响应,将响应的内容添加到聊天记录中。 清空文本输入框,准备下一次聊天。 这个 HTML 模板只是个简单的框架,具体的逻辑实现还需要你在服务器端进行开发。 感谢您阅读这篇文章,希望能帮助到您。在这篇文章中,我们介绍了如何将 ChatGPT 部署到网站上,并使用 jQuery 和 Bootstrap 构建聊天系统的界面。如果您有任何疑问或建议,欢迎在评论区留言。最后,如果这篇文章对您有所帮助,希望能给个打赏鼓励一下作者。 https://jdjwzx233.cn/support。

2022/12/24
articleCard.readMore

远程桌面控制器-用c++实现

写一个远程桌面控制器是一个非常复杂的任务,需要熟悉许多网络协议、图像处理技术以及用户界面设计等知识。这里给出的是一个基本的框架,你可以在此基础上进行扩展和完善。 首先,我们需要用到一些库来帮助我们实现远程桌面控制器。在这里,我们假设你使用的是 Windows 系统,并使用了以下几个库: WinSock:用于实现网络通信。 GDI+:用于处理图像。 MFC:用于创建图形用户界面。 下面是使用这些库编写远程桌面控制器的基本步骤: 创建一个 MFC 应用程序。 使用 WinSock 库创建一个网络连接。 使用 GDI+ 库获取远程桌面的屏幕截图。 将屏幕截图显示在 MFC 窗口中。 为用户提供一组控制命令,例如鼠标移动、鼠标单击、键盘输入等。 使用 WinSock 库将用户的控制命令发送到远程桌面。 下面是使用这些库编写远程桌面控制器的示例代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 #include <winsock2.h> #include <gdiplus.h> #include <afxwin.h> // 包含 MFC 的头文件 using namespace Gdiplus; // 定义一个 Socket 类,用于封装网络通信相关的操作 class Socket { private: WSADATA m_wsaData; SOCKET m_sock; sockaddr_in m_serverAddr; public: Socket() : m_sock(INVALID_SOCKET) {} // 初始化 WinSock 库 bool Init() { if (WSAStartup(MAKEWORD(2, 2), &m_wsaData) != 0) { return false; } return true; } // 创建套接字 bool Create(int af, int type, int protocol) { m_sock = socket(af, type, protocol); if (m_sock == INVALID_SOCKET) { return false; } return true; } // 连接到服务器 bool Connect(const char* ip, unsigned short port) { m_serverAddr.sin_family = AF_INET; m_serverAddr.sin_port = htons(port); m_serverAddr.sin_addr.S_un.S_addr = inet_addr(ip); if (connect(m_sock, (sockaddr*)&m_serverAddr, sizeof(m_serverAddr)) == SOCKET_ERROR) { return false; } return true; } // 发送数据 int Send(const char* buf, int len) { return send(m_sock, buf, len, 0); } // 接收数据 int Receive(char* buf, int len) { return recv(m_sock, buf, len, 0); } // 关闭套接字 void Close() { closesocket(m_sock); m_sock = INVALID_SOCKET; } // 清理 WinSock 库 void Cleanup() { WSACleanup(); } }; // 定义一个 RemoteDesktop 类,用于控制远程桌面 class RemoteDesktop { private: Socket m_socket; // 用于网络通信的套接字 Image* m_image; // 当前屏幕截图 public: RemoteDesktop() : m_image(NULL) {} // 连接到远续桌面服务器 bool Connect(const char* ip, unsigned short port) { if (!m_socket.Init()) { return false; } if (!m_socket.Create(AF_INET, SOCK_STREAM, IPPROTO_TCP)) { return false; } if (!m_socket.Connect(ip, port)) { return false; } return true; } // 断开与远程桌面服务器的连接 void Disconnect() { m_socket.Close(); m_socket.Cleanup(); delete m_image; m_image = NULL; } // 获取远程桌面的屏幕截图 bool GetScreenshot() { // 先发送获取屏幕截图的命令 const char* cmd = "screenshot"; m_socket.Send(cmd, strlen(cmd)); // 接收屏幕截图的大小 int size; m_socket.Receive((char*)&size, sizeof(size)); // 分配内存空间,准备接收屏幕截图的数据 char* data = new char[size]; // 接收屏幕截图的数据 int bytesReceived = 0; while (bytesReceived < size) { int count = m_socket.Receive(data + bytesReceived, size - bytesReceived); if (count <= 0) { delete[] data; return false; } bytesReceived += count; } // 将接收到的数据转换为 GDI+ 图像 delete m_image; m_image = new Image(data, size); delete[] data; return true; } // 获取当前屏幕截图 Image* GetImage() const { return m_image; } // 发送鼠标移动命令 void MoveMouse(int x, int y) { // 封装命令格式,发送命令 const char* cmd = "mouse move"; m_socket.Send(cmd, strlen(cmd)); m_socket.Send((char*)&x, sizeof(x)); m_socket.Send((char*)&y, sizeof(y)); } // 发送鼠标单击命令 void ClickMouse(int x, int y) { // 封装命令格式,发送命令 const char* cmd = "mouse click"; m_socket.Send(cmd, strlen(cmd)); m_socket.Send((char*)&x, sizeof(x)); m_socket.Send((char*)&y, sizeof(y)); } // 发送键盘输入命令 void InputKey(int keyCode) { // 封装命令格式,发送命令 const char* cmd = "key input"; m_socket.Send(cmd, strlen(cmd)); m_socket.Send((char*)&keyCode, sizeof(keyCode)); } }; // 定义一个 RemoteDesktopDialog 类,用于显示远程桌面的界面 class RemoteDesktopDialog : public CDialog { private: RemoteDesktop m_rd; // 用于控制远程桌面的对象 public: // 使用 MFC 对话框的基本操作 RemoteDesktopDialog() : CDialog(IDD_DIALOG1) {} protected: virtual void DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); } public: // 连接到远程桌面服务器 bool Connect(const char* ip, unsigned short port) { return m_rd.Connect(ip, port); } // 断开与远程桌面服务器的连接 void Disconnect() { m_rd.Disconnect(); } protected: // 绘制远程桌面的界面 afx_msg void OnPaint() { CPaintDC dc(this); // 用于绘制的设备上下文 CRect rect; GetClientRect(&rect); // 获取对话框的客户区域 // 获取屏幕截图,并绘制到界面上 Image* image = m_rd.GetImage(); if (image != NULL) { Graphics graphics(dc); graphics.DrawImage(image, rect); } } // 处理鼠标移动事件 afx_msg void OnMouseMove(UINT nFlags, CPoint point) { m_rd.MoveMouse(point.x, point.y); } // 处理鼠标单击事件 afx_msg void OnLButtonDown(UINT nFlags, CPoint point) { m_rd.ClickMouse(point.x, point.y); } // 处理键盘输入事件 afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) { m_rd.InputKey(nChar); } DECLARE_MESSAGE_MAP() }; BEGIN_MESSAGE_MAP(RemoteDesktopDialog, CDialog) ON_WM_PAINT() ON_WM_MOUSEMOVE() ON_WM_LBUTTONDOWN() ON_WM_KEYDOWN() END_MESSAGE_MAP() int main() { // 初始化 GDI+ GdiplusStartupInput gdiplusStartupInput; ULONG_PTR gdiplusToken; GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); // 创建对话框并运行 RemoteDesktopDialog dlg; dlg.DoModal(); // 清理 GDI+ GdiplusShutdown(gdiplusToken); return 0; } 在这段代码中,我们定义了三个类:Socket、RemoteDesktop 和 RemoteDesktopDialog。Socket 类封装了网络通信的相关操作,RemoteDesktop 类用于控制远程桌面,RemoteDesktopDialog 类用于显示远程桌面的界面。 使用这个远程桌面控制器的流程如下: 调用 Socket 类的 Init 函数初始化 WinSock 库。 调用 Socket 类的 Create 函数创建一个套接字。 调用 Socket 类的 Connect 函数连接到远程桌面服务器。 调用 RemoteDesktop 类的 GetScreenshot 函数获取远程桌面的屏幕截图。 调用 RemoteDesktop 类的 MoveMouse、ClickMouse 或 InputKey 函数发送控制命令。 重复步骤 4 和 5,实时更新远程桌面的屏幕截图并发送控制命令。 当远程桌面控制结束时,调用 RemoteDesktop 类的 Disconnect 函数断开与远程桌面服务器的连接,并调用 Socket 类的 Cleanup 函数清理 WinSock 库。 需要注意的是,这段代码使用了 MFC 库来绘制界面,因此需要在 Visual Studio 中创建一个 MFC 应用程序,并在对话框资源中添加一个对话框。然后将上面的代码放入主窗口类的 .cpp 文件中,并在 .h 文件中声明相应的消息映射函数。 以下是服务端代码: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 #include <Windows.h> #include <GdiPlus.h> #include <winsock2.h> #include<iostream> #pragma comment(lib, "gdiplus.lib") #pragma comment(lib, "ws2_32.lib") using namespace std; using namespace Gdiplus; // 定义一个 Socket 类,用于封装网络通信相关的操作 class Socket { private: WSADATA m_wsaData; SOCKET m_sock; sockaddr_in m_serverAddr; sockaddr_in m_clientAddr; public: Socket() : m_sock(INVALID_SOCKET) {} // 初始化 WinSock 库 bool Init() { if (WSAStartup(MAKEWORD(2, 2), &m_wsaData) != 0) { return false; } return true; } // 创建套接字 bool Create(int af, int type, int protocol) { m_sock = socket(af, type, protocol); if (m_sock == INVALID_SOCKET) { return false; } return true; } // 绑定套接字到本地地址和端口 bool Bind(unsigned short port) { memset(&m_serverAddr, 0, sizeof(m_serverAddr)); m_serverAddr.sin_family = AF_INET; m_serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); m_serverAddr.sin_port = htons(port); if (bind(m_sock, (sockaddr*)&m_serverAddr, sizeof(m_serverAddr)) == SOCKET_ERROR) { return false; } return true; } // 监听套接字 bool Listen(int backlog) { if (listen(m_sock, backlog) == SOCKET_ERROR) { return false; } return true; } // 接受客户端的连接 bool Accept(Socket& client) { int addrLen = sizeof(m_clientAddr); client.m_sock = accept(m_sock, (sockaddr*)&m_clientAddr, &addrLen); if (client.m_sock == INVALID_SOCKET) { return false; } return true; } // 接收数据 int Receive(char* buffer, int len) { return recv(m_sock, buffer, len, 0); } // 发送数据 int Send(const char* buffer, int len) { return send(m_sock, buffer, len, 0); } // 关闭套接字 void Close() { closesocket(m_sock); m_sock = INVALID_SOCKET; } // 清理 WinSock 库 void Cleanup() { WSACleanup(); } }; // 定义一个 RemoteDesktopServer 类,用于提供远程桌面服务 class RemoteDesktopServer { private: Socket m_socket; // 用于网络通信的套接字 public: // 初始化远程桌面服务器 bool Init(unsigned short port) { if (!m_socket.Init()) { return false; } if (!m_socket.Create(AF_INET, SOCK_STREAM, IPPROTO_TCP)) { return false; } if (!m_socket.Bind(port)) { return false; } if (!m_socket.Listen(10)) { return false; } return true; } // 运行远程桌面服务器 void Run() { // 不断循环,接受客户端的连接 while (true) { Socket client; if (!m_socket.Accept(client)) { continue; } // 为客户端创建一个线程,用于处理客户端的请求 HANDLE hThread = CreateThread(NULL, 0, ClientThreadProc, &client, 0, NULL); if (hThread == NULL) { client.Close(); continue; } CloseHandle(hThread); } } private: // 客户端线程的回调函数,用于处理客户端的请求 static DWORD WINAPI ClientThreadProc(LPVOID lpParam) { Socket* pClient = (Socket*)lpParam; // 不断循环,处理客户端的请求 while (true) { // 接收客户端的命令 char cmd[256]; int len = pClient->Receive(cmd, sizeof(cmd)); if (len <= 0) { break; } // 根据命令类型执行相应的操作 if (strcmp(cmd, "screenshot") == 0) { // 处理屏幕截图请求 HandleScreenshotRequest(*pClient); } else if (strcmp(cmd, "mouse move") == 0) { // 处理鼠标移动请求 int x, y; pClient->Receive((char*)&x, sizeof(x)); pClient->Receive((char*)&y, sizeof(y)); HandleMouseMoveRequest(x, y); } else if (strcmp(cmd, "mouse click") == 0) { // 处理鼠标单击请求 int x, y; pClient->Receive((char*)&x, sizeof(x)); pClient->Receive((char*)&y, sizeof(y)); HandleMouseClickRequest(x, y); } else if (strcmp(cmd, "key input") == 0) { // 处理键盘输入请求 char key; pClient->Receive(&key, sizeof(key)); HandleKeyInputRequest(key); } else { break; } } // 关闭客户端的套接字 pClient->Close(); delete pClient; return 0; } // 处理屏幕截图请求 static void HandleScreenshotRequest(Socket& client) { // 获取屏幕的宽高 int width = GetSystemMetrics(SM_CXSCREEN); int height = GetSystemMetrics(SM_CYSCREEN); // 创建内存 DC HDC hdcMem = CreateCompatibleDC(NULL); if (hdcMem == NULL) { return; } // 创建位图 HBITMAP hbm = CreateCompatibleBitmap(GetDC(NULL), width, height); if (hbm == NULL) { DeleteDC(hdcMem); return; } // 将位图选入内存 DC HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, hbm); if (hbmOld == NULL) { DeleteObject(hbm); DeleteDC(hdcMem); return; } // 将屏幕拷贝到内存 DC if (!BitBlt(hdcMem, 0, 0, width, height, GetDC(NULL), 0, 0, SRCCOPY)) { SelectObject(hdcMem, hbmOld); DeleteObject(hbm); DeleteDC(hdcMem); return; } // 将内存 DC 的图像保存到缓冲区 BITMAPINFOHEADER bih; memset(&bih, 0, sizeof(bih)); bih.biSize = sizeof(bih); bih.biWidth = width; bih.biHeight = -height; bih.biPlanes = 1; bih.biBitCount = 24; bih.biCompression = BI_RGB; BYTE* pBuf = NULL; HBITMAP hbmDib = CreateDIBSection(hdcMem, (BITMAPINFO*)&bih, DIB_RGB_COLORS, (void**)&pBuf, NULL, 0); if (hbmDib == NULL) { SelectObject(hdcMem, hbmOld); DeleteObject(hbm); DeleteDC(hdcMem); return; } // 将内存 DC 的图像复制到位图中 if (!SelectObject(hdcMem, hbmDib)) { DeleteObject(hbmDib); SelectObject(hdcMem, hbmOld); DeleteObject(hbm); DeleteDC(hdcMem); return; } // 将位图的图像转换为 JPEG 格式并发送到客户端 if (!SendScreenshot(client, pBuf, width, height)) { DeleteObject(hbmDib); SelectObject(hdcMem, hbmOld); DeleteObject(hbm); DeleteDC(hdcMem); return; } // 清理资源 DeleteObject(hbmDib); SelectObject(hdcMem, hbmOld); DeleteObject(hbm); DeleteDC(hdcMem); } // 将位图的图像转换为 JPEG 格式并发送到客户端 static bool SendScreenshot(Socket& client, BYTE* pBuf, int width, int height) { // 初始化 GDI+ GdiplusStartupInput gdiplusStartupInput; ULONG_PTR gdiplusToken; GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); // 将位图的图像转换为 JPEG 格式 Bitmap bmp(width, height, width * 3, PixelFormat24bppRGB, pBuf); CLSID clsid; GetEncoderClsid(L"image/jpeg", &clsid); IStream* pStream = NULL; bmp.Save(L"screenshot.jpg", &clsid, NULL); if (CreateStreamOnHGlobal(NULL, TRUE, &pStream) != S_OK) { GdiplusShutdown(gdiplusToken); return false; } bmp.Save(pStream, &clsid, NULL); HGLOBAL hGlobal = NULL; // 修改为 HGLOBAL 类型 if (GetHGlobalFromStream(pStream, &hGlobal) != S_OK) // 修改为 HGLOBAL 类型 { pStream->Release(); GdiplusShutdown(gdiplusToken); return false; } ULONG cbSize = GlobalSize(hGlobal); // 修改为 HGLOBAL 类型 BYTE* pJpegBuf = (BYTE*)GlobalLock(hGlobal); // 修改为 HGLOBAL 类型 if (pJpegBuf == NULL) { pStream->Release(); GdiplusShutdown(gdiplusToken); return false; } LARGE_INTEGER li; li.QuadPart = 0; if (pStream->Seek(li, STREAM_SEEK_SET, NULL) != S_OK) { GlobalFree(pJpegBuf); pStream->Release(); GdiplusShutdown(gdiplusToken); return false; } if (pStream->Read(pJpegBuf, cbSize, NULL) != S_OK) { GlobalFree(pJpegBuf); pStream->Release(); GdiplusShutdown(gdiplusToken); return false; } pStream->Release(); GdiplusShutdown(gdiplusToken); // 将 JPEG 数据的长度发送到客户端 if (client.Send((char*)&cbSize, sizeof(cbSize)) <= 0) { GlobalFree(pJpegBuf); return false; } // 将 JPEG 数据发送到客户端 if (client.Send((char*)pJpegBuf, cbSize) <= 0) { GlobalFree(pJpegBuf); return false; } // 清理资源 GlobalFree(pJpegBuf); return true; } // 获取图像编码器的 CLSID static void GetEncoderClsid(const WCHAR* format, CLSID* pClsid) { UINT num = 0, size = 0; GetImageEncodersSize(&num, &size); if (size == 0) { return; } ImageCodecInfo* pImageCodecInfo = (ImageCodecInfo*)malloc(size); if (pImageCodecInfo == NULL) { return; } GetImageEncoders(num, size, pImageCodecInfo); for (UINT i = 0; i < num; ++i) { if (wcscmp(pImageCodecInfo[i].MimeType, format) == 0) { *pClsid = pImageCodecInfo[i].Clsid; free(pImageCodecInfo); return; } } free(pImageCodecInfo); } // 处理鼠标移动请求 static void HandleMouseMoveRequest(int x, int y) { // 获取屏幕的宽高 int width = GetSystemMetrics(SM_CXSCREEN); int height = GetSystemMetrics(SM_CYSCREEN); // 计算相对于屏幕的坐标 double fx = (double)x / 65535.0; // 移动鼠标 SetCursorPos(x, y); } // 处理鼠标单击请求 static void HandleMouseClickRequest(int x, int y) { // 获取屏幕的宽高 int width = GetSystemMetrics(SM_CXSCREEN); int height = GetSystemMetrics(SM_CYSCREEN); // 计算相对于屏幕的坐标 double fx = (double)x / 65535.0; double fy = (double)y / 65535.0; int cx = (int)(fx * width); int cy = (int)(fy * height); // 移动鼠标 SetCursorPos(cx, cy); // 发送鼠标左键单击消息 INPUT input; memset(&input, 0, sizeof(input)); input.type = INPUT_MOUSE; input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP; SendInput(1, &input, sizeof(input)); } // 处理键盘输入请求 static void HandleKeyInputRequest(char key) { // 获取键盘的输入模式 HKL layout = GetKeyboardLayout(0); UINT vk = MapVirtualKeyExA(VkKeyScanExA(key, layout), 0, layout); // 发送键盘输入消息 INPUT input; memset(&input, 0, sizeof(input)); input.type = INPUT_KEYBOARD; input.ki.wVk = vk; SendInput(1, &input, sizeof(input)); } private: Socket m_socket; // 监听套接字 }; int main() { RemoteDesktopServer server; if (!server.Init(5555)) { cout<<"启动服务器失败!"<<endl; return 1; } server.Run(); return 0; } 希望这些代码能帮到你!

2022/12/23
articleCard.readMore

用c++写图像界面软件(QT)

在 C++ 中编写图形界面软件的方法有很多种,下面介绍一种使用 Qt 库来编写图形界面软件的方法。 首先,需要安装 Qt 开发环境。你可以在 Qt 官网下载安装包,并按照安装说明进行安装。 在设计界面时,你可以使用拖放控件的方式,将控件放到界面上。然后,你可以使用属性编辑器来设置控件的各种属性,例如大小、颜色、字体等。 在代码中,你可以使用信号和槽机制来连接界面中的控件和应用程序的功能。例如,可以让按钮的单击信号连接到一个槽函数,从而在按钮被单击时执行特定的操作。 下面是一个简单的示例代码,显示了如何使用 Qt 创建一个带有一个按钮的窗口,并在按钮被单击时弹出对话框: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include <QApplication> #include <QPushButton> #include <QMessageBox> int main(int argc, char *argv[]) { QApplication app(argc, argv); QPushButton button("Click me"); QObject::connect(&button, &QPushButton::clicked, []() { QMessageBox::information(nullptr, "Title", "Hello, World!"); }); button.show(); return app.exec(); } 接下来,我们来看如何在代码中添加菜单栏。 首先,在界面设计器中添加一个菜单栏控件。然后,在代码中使用 QMenuBar 类创建一个菜单栏对象,并将其添加到窗口中。 接下来,你可以使用 QMenu 类创建菜单,并添加到菜单栏中。你还可以使用 QAction 类创建菜单项,并添加到菜单中。 例如,下面的代码演示了如何创建一个带有 “文件” 菜单的菜单栏,其中包含 “打开” 和 “保存” 两个菜单项: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include <QApplication> #include <QMainWindow> #include <QMenuBar> #include <QMenu> #include <QAction> int main(int argc, char *argv[]) { QApplication app(argc, argv); QMainWindow window; window.setWindowTitle("My App"); QMenuBar *menuBar = new QMenuBar(&window); QMenu *fileMenu = new QMenu("File", menuBar); QAction *openAction = new QAction("Open", fileMenu); QAction *saveAction = new QAction("Save", fileMenu); fileMenu->addAction(openAction); fileMenu->addAction(saveAction); menuBar->addMenu(fileMenu); window.setMenuBar(menuBar); window.show(); return app.exec(); } 为了在图形界面软件中显示图片,你可以使用 Qt 中的 QLabel 控件。 首先,在界面设计器中添加一个 QLabel 控件。然后,在代码中,你可以使用 QLabel 类的 setPixmap 方法来设置要显示的图片。 例如,下面的代码演示了如何在图形界面中显示一张名为 “image.png” 的图片: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <QApplication> #include <QLabel> #include <QPixmap> int main(int argc, char *argv[]) { QApplication app(argc, argv); QLabel label; QPixmap pixmap("image.png"); label.setPixmap(pixmap); label.show(); return app.exec(); } 注意,在使用 QLabel 显示图片时,需要使用 QPixmap 类来加载图片文件。 如果你想要在图形界面中显示动态图像,你可以使用 Qt 中的 QMovie 类。 QMovie 类可以用来播放 GIF 动画。 例如,下面的代码演示了如何在图形界面中播放名为 “animation.gif” 的 GIF 动画: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include <QApplication> #include <QLabel> #include <QMovie> int main(int argc, char *argv[]) { QApplication app(argc, argv); QLabel label; QMovie movie("animation.gif"); label.setMovie(&movie); movie.start(); label.show(); return app.exec(); } 现在,我们来看如何在图形界面软件中添加图表。 首先,你需要在界面设计器中添加一个图表控件。Qt 中有多种图表控件可供选择,包括柱状图、折线图、饼图等。 然后,你可以使用 QChart 类创建图表对象,并使用 QAbstractSeries 类的子类(例如 QLineSeries 、 QBarSeries 等)创建数据序列。你还可以使用 QValueAxis 类创建坐标轴,并将它们添加到图表中。 例如,下面的代码演示了如何创建一个带有两个数据序列的柱状图: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #include <QApplication> #include <QChart> #include <QChartView> #include <QBarSeries> #include <QBarSet> #include <QValueAxis> int main(int argc, char *argv[]) { QApplication app(argc, argv); QBarSet *set1 = new QBarSet("Data 1"); *set1 << 1 << 2 << 3 << 4 << 5; QBarSet *set2 = new QBarSet("Data 2"); *set2 << 5 << 4 << 3 << 2 << 1; QBarSeries *series = new QBarSeries(); series->append(set1); series->append(set2); QChart *chart = new QChart(); chart->addSeries(series); chart->setTitle("Example Chart"); QValueAxis *axisX = new QValueAxis(); axisX->setRange(0, 6); axisX->setLabelFormat("%g"); chart->addAxis(axisX, Qt::AlignBottom); series->attachAxis(axisX); QValueAxis *axisY = new QValueAxis(); axisY->setRange(0, 6); axisY->setTitleText("Y-axis"); chart->addAxis(axisY, Qt::AlignLeft); series->attachAxis(axisY); QChartView chartView(chart); chartView.setRenderHint(QPainter::Antialiasing); chartView.resize(400, 300); chartView.show(); return app.exec(); } 在这段代码中,我们首先创建了两个数据序列(使用 QBarSet 类),然后将它们添加到一个 QBarSeries 对象中。接着,我们创建了一个 QChart 对象,并将数据序列添加到图表中。最后,我们创建了两个坐标轴(使用 QValueAxis 类),并将它们添加到图表中。 接下来,让我们来看如何在图形界面软件中添加交互式图表。 为了实现交互式图表,你可以使用 Qt 中的 QChartView 类。 QChartView 类提供了一些内置的交互工具,包括缩放、拖拽、轴调整等。 要使用 QChartView 类,你需要先创建一个 QChart 对象,然后将其传递给 QChartView 的构造函数。例如,下面的代码演示了如何创建一个交互式的折线图: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <QApplication> #include <QChart> #include <QChartView> #include <QLineSeries> #include <QValueAxis> int main(int argc, char *argv[]) { QApplication app(argc, argv); QLineSeries *series = new QLineSeries(); *series << QPointF(0, 0) << QPointF(1, 1) << QPointF(2, 4) << QPointF(3, 9); QChart *chart = new QChart(); chart->addSeries(series); chart->setTitle("Simple line chart example"); chart->createDefaultAxes(); QChartView chartView(chart); chartView.setRenderHint(QPainter::Antialiasing); chartView.resize(400, 300); chartView.show(); return app.exec(); } 在这段代码中,我们首先创建了一个数据序列(使用 QLineSeries 类),然后将它添加到一个 QChart 对象中。接着,我们调用 QChart 类的 createDefaultAxes 方法来创建默认的坐标轴。最后,我们创建了一个 QChartView 对象,并将图表传递给它。 接下来,让我们来看如何在图形界面软件中使用 OpenCV 读取和显示图像。 首先,你需要安装 OpenCV 库。在 Windows 上,你可以使用 vcpkg 工具安装 OpenCV。在 Linux 上,你可以使用包管理器安装 OpenCV。 然后,你需要在 Qt 工程中添加 OpenCV 的头文件和库文件。具体方法可以参考 Qt 文档。 接着,你就可以使用 OpenCV 的 cv::Mat 类来读取和显示图像了。例如,下面的代码演示了如何使用 OpenCV 读取名为 “image.png” 的图片并在图形界面中显示: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <QApplication> #include <QLabel> #include <opencv2/opencv.hpp> int main(int argc, char *argv[]) { QApplication app(argc, argv); cv::Mat image = cv::imread("image.png"); QImage qimage = QImage((const unsigned char*)(image.data), image.cols, image.rows, image.step, QImage::Format_RGB888); QLabel label; label.setPixmap(QPixmap::fromImage(qimage)); label.show(); return app.exec(); } 在这段代码中,我们使用 OpenCV 的 imread 函数读取图片,然后将图片数据转换为 QImage 对象。最后,我们使用 QLabel 类显示图片。 注意,如果你想要在图形界面软件中显示动态图像,你可以使用 Qt 中的 QTimer 类来实现。 例如,下面的代码演示了如何使用 OpenCV 读取视频并在图形界面中显示: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include <QApplication> #include <QLabel> #include <QTimer> #include <opencv2/opencv.hpp> int main(int argc, char *argv[]) { QApplication app(argc, argv); cv::VideoCapture capture("video.mp4"); QLabel label; QTimer timer; QObject::connect(&timer, &QTimer::timeout, [&]() { cv::Mat frame; capture >> frame; if (frame.empty()) { capture.set(cv::CAP_PROP_POS_AVI_RATIO, 0); capture >> frame; } QImage qimage = QImage((const unsigned char*)(frame.data), frame.cols, frame.rows, frame.step, QImage::Format_RGB888); label.setPixmap(QPixmap::fromImage(qimage)); }); timer.start(1000 / 30); label.show(); return app.exec(); } 在这段代码中,我们使用 OpenCV 的 VideoCapture 类读取视频,然后使用 QTimer 类定时获取视频帧并更新图像。注意,我们使用 QImage 类将视频帧转换为图像,并使用 QLabel 类显示图像。 这是一个简单的示例,你还可以自己添加更多的功能,例如暂停、快进、播放速度调整等。 希望这些信息对你有帮助!如果喜欢的话,可以在下方打赏作者哦

2022/12/22
articleCard.readMore

C++中常用的排序算法

在 C++ 中,常用的排序算法包括: 冒泡排序(Bubble Sort) 冒泡排序是一种简单的排序算法,它通过重复地遍历要排序的数列并比较相邻的两个数来排序。 代码如下: 1 2 3 4 5 6 7 8 9 10 11 void bubbleSort(int arr[], int n) { for (int i = 0; i < n - 1; i++) { for (int j = 0; j < n - i - 1; j++) { if (arr[j] > arr[j + 1]) { int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; } } } } 选择排序(Selection Sort) 选择排序是一种简单的排序算法,它通过遍历数列来找到最小值并将其放到数列的起始位置,然后再从剩余未排序的数列中继续寻找最小值并放到已排序的数列末尾,以此类推直到所有数列排序完毕。 代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 void selectionSort(int arr[], int n) { for (int i = 0; i < n - 1; i++) { int minIndex = i; for (int j = i + 1; j < n; j++) { if (arr[j] < arr[minIndex]) { minIndex = j; } } int temp = arr[i]; arr[i] = arr[minIndex]; arr[minIndex] = temp; } } 插入排序(Insertion Sort) 插入排序是一种简单的排序算法,它通过将数列分成已排序和未排序两部分,然后从未排序的数列中取出第一个数,并插入到已排序的数列中的适当位置,使得已排序的数列仍然有序。 代码如下: 1 2 3 4 5 6 7 8 9 10 11 void insertionSort(int arr[], int n) { for (int i = 1; i < n; i++) { int key = arr[i]; int j = i - 1; while (j >= 0 && arr[j] > key) { arr[j + 1] = arr[j]; j--; } arr[j + 1] = key; } } 归并排序(Merge Sort) 归并排序是一种分治算法,它通过递归地将数列分成两半,然后将两半分别排序,最后将两半合并起来得到最终的排序结果。 代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 void merge(int arr[], int left[], int leftSize, int right[], int rightSize) { int i = 0, j = 0, k = 0; while (i < leftSize && j < rightSize) { if (left[i] < right[j]) { arr[k++] = left[i++]; } else { arr[k++] = right[j++]; } } while (i < leftSize) { arr[k++] = left[i++]; } while (j < rightSize) { arr[k++] = right[j++]; } } void mergeSort(int arr[], int n) { if (n < 2) return; int mid = n / 2; int left[mid]; int right[n - mid]; for (int i = 0; i < mid; i++) { left[i] = arr[i]; } for (int i = mid; i < n; i++) { right[i - mid] = arr[i]; } mergeSort(left, mid); mergeSort(right, n - mid); merge(arr, left, mid, right, n - mid); } 快速排序(Quick Sort) 快速排序是一种分治算法,它通过选择一个基准元素,将数列分成两部分,使得左边的所有元素都小于基准元素,右边的所有元素都大于基准元素,然后递归地对两部分进行快速排序,最终得到有序的数列。 代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 int partition(int arr[], int low, int high) { int pivot = arr[high]; int i = low - 1; for (int j = low; j <= high - 1; j++) { if (arr[j] < pivot) { i++; int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } int temp = arr[i + 1]; arr[i + 1] = arr[high]; arr[high] = temp; return i + 1; } void quickSort(int arr[], int low, int high) { if (low < high) { int pi = partition(arr, low, high); quickSort(arr, low, pi - 1); quickSort(arr, pi + 1, high); } } 这些排序算法的时间复杂度各不相同,在不同情况下可能会有所差异。你可以根据自己的需要来选择适合的排序算法。 希尔排序(Shell Sort) 希尔排序是一种插入排序的变种,它通过设置一个间隔来将数列划分成若干个小的数列,然后对每个小数列进行插入排序,最终得到有序的数列。 代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 void shellSort(int arr[], int n) { for (int gap = n / 2; gap > 0; gap /= 2) { for (int i = gap; i < n; i++) { int temp = arr[i]; int j; for (j = i; j >= gap && arr[j - gap] > temp; j -= gap) { arr[j] = arr[j - gap]; } arr[j] = temp; } } } 堆排序(Heap Sort) 堆排序是一种选择排序的变种,它通过建立一个堆来选择最大(或最小)的元素并放到数列末尾,然后将剩余的数列重新建堆并继续选择最大(或最小)的元素,以此类推直到所有数列排序完毕。 代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 void heapify(int arr[], int n, int i) { int largest = i; int left = 2 * i + 1; int right = 2 * i + 2; if (left < n && arr[left] > arr[largest]) { largest = left; } if (right < n && arr[right] > arr[largest]) { largest = right; } if (largest != i) { int temp = arr[i]; arr[i] = arr[largest]; arr[largest] = temp; heapify(arr, n, largest); } } void heapSort(int arr[], int n) { for (int i = n / 2 - 1; i >= 0; i--) { heapify(arr, n, i); } for (int i = n - 1; i >= 0; i--) { int temp = arr[0]; arr[0] = arr[i]; arr[i] = temp; heapify(arr, i, 0); } } 计数排序(Counting Sort) 计数排序是一种非比较排序算法,它通过计算数列中每个数出现的次数来排序。它的时间复杂度为 O (n),因此在数据范围较小的情况下可以使用计数排序。 代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 void countingSort(int arr[], int n, int maxValue) { int counts[maxValue + 1]; for (int i = 0; i <= maxValue; i++) { counts[i] = 0; } for (int i = 0; i < n; i++) { counts[arr[i]]++; } for (int i = 0, j = 0; i <= maxValue; i++) { while (counts[i]-- > 0) { arr[j++] = i; } } } 以上是 C++ 中的几种排序算法的代码,希望能帮到你。

2022/12/22
articleCard.readMore

《简爱》每章概括+赏析

# 每章概括: # 第一章: 简・爱的父亲是个穷牧师,当她还在幼年时,父母就染病双双去世。简・爱被送到盖茨海德庄园的舅母里德太太家抚养. # 第二章: 舅父里德先生在红房子中去世后,简爱过了 10 年受尽歧视和虐待的生活。一次,由于反抗表哥的殴打,简被关进了红房子。肉体上的痛苦和心灵上的屈辱和恐惧,使她大病了一场。 # 第三章: 舅母把她视作眼中钉,并把她和自己的孩子隔离开来,并决定把她送进达罗沃德孤儿院。 # 第四章: 由于她与舅母的对抗更加公开和坚决,里德太太加快了送简爱去孤儿院的脚步,为了赶走简爱,她在勃洛克赫斯特先生面前处处中伤简爱,毁坏简爱的名誉。 # 第五章: 孤儿院教规严厉,生活艰苦,院长是个冷酷的伪君子。他用种种办法从精神和肉体上摧残孤儿。简爱吃不饱、穿不暖,继续受尽非人的折磨。 # 第六章: 简・爱与孤儿海伦结成好友,教师潭泊尔小姐也很关心她。 # 第七章: 简爱失手打碎了石板,被惩罚站在凳子上,当众受到羞辱,是海伦的微笑给了简爱力量。 # 第八章: 伤心的简爱到学校下课时才从凳子上下来,悲愤不已,海伦给她端来咖啡和面包,并不断开导她。谭波小姐也来看望她,并与海伦谈古论今,使简爱佩服不已。 # 第九章: 在孤儿院里一场传染性的斑疹伤寒,夺走了许多孤儿的生命,海伦就在这场伤寒中死去,这对简・爱 打击很大。 # 第十章: 斑疹伤寒使孤儿院有了大规模的改善。简在新的环境下接受了六年的教育,并在这所学校任教两年。由于谭波尔儿小姐的离开,简厌倦了孤儿院里的生活,登广告谋求家庭教师的职业。 # 第十一章: 桑菲尔德庄园的女管家聘用了她。偌大的宅第只有一个不到 10 岁的女孩阿黛拉・瓦朗,罗切斯特先生是她的保护人,她是简爱的学生。简爱来到了桑费尔德庄园,那里的一切很庄严和气派。 # 第十二章: 一天黄昏,简・爱外出散步,邂逅刚从国外归来的主人,这是他们第一次见面。罗切斯特从受惊的马上摔了下来,简急忙上前去扶他,回到家后简才知道他便是庄园主罗切斯特。 # 第十三章: 阿黛尔很不容易教,不专心,处处找借口去寻找罗伯斯特先生。罗伯斯特先生与简爱面对面交流,了解简爱的过去,并对简爱的画做出评价。 # 第十四章: 她发现她的主人是个性格忧郁、喜怒无常的人,对她的态度时好时坏。整幢房子沉郁空旷。 # 第十五章: 夜里,简・爱简被一阵奇怪的笑声惊醒,发现罗切斯特的房门开着,床上着了火,她叫醒罗切斯特并扑灭火。罗切斯特告诉简・爱三楼住着一个女栽缝格雷斯・普尔,她神经错乱,时常发出令人毛骨悚然的狂笑声,并要她对此事严守秘密。 # 第十六章: 简爱苦思冥想理不清头绪,胡乱猜测缘由,想见到罗伯斯特先生又盼不到他。第十七章:罗切斯特回来后经常举行家宴,桑费尔德庄园上上下下开始忙碌起来。在一次家宴上他向一位名叫英格拉姆的漂亮小姐大献殷勤,简被召进客厅,却受到布兰奇母女的冷遇,她忍受屈辱,离开客厅。 # 第十八章: 在宴会上罗切斯特坚持要简・爱也到客厅里去,客人们对简・爱的态度十分傲慢,而罗切斯特却邀请简・爱跳舞,此时罗切斯特已爱上简,而简也感觉到自己对罗切斯特产生感情。 # 第十九章: 罗切斯特外出,家里来了一个蒙着盖头的吉卜赛人。当轮到给简・爱算命时,简・爱发现这个神秘的吉卜赛人就是罗切斯特,他想借此试探简对他的感情。 # 第二十章: 庄园里又来了个名梅森的陌生人,当晚他被三楼的神秘女人咬伤了,简帮罗切斯特把他秘密送走。 # 第二十一章: 不久,里德太太派人来找简,说她病危要见简一面。回到舅母家中,里德太太给她一封信,这封信是三年前简的叔父寄来的,向她打听侄女的消息,并把自己的遗产交给简・爱。里德太太谎称简在孤儿院病死了,直到临终前才良心发现把真相告诉简。 # 第二十二章: 简爱又回到桑费尔德庄园感觉像回到家一样。人们都在猜测罗切斯特会向布兰奇小姐求婚。 # 第二十三章: 罗切斯特向简爱求爱,简爱答应了,心里充满了幸福感。 # 第二十四章: 罗切斯特与简爱筹备婚礼。罗伯斯特很宠简爱,简爱视罗贝斯特为她的整个世界,他是简爱的偶像。 # 第二十五章: 婚礼前夜,简・爱从梦中惊醒,看到一个身材高大、面目可憎的女人正在戴她的婚纱,然后把婚纱的面罩撕成碎片。罗切斯特告诉她那不过是一个梦,第二天当简醒来时发现婚纱的面罩真的成了碎片。 # 第二十六章: 婚礼如期举行,一位不速之客闯进了教堂,声称婚礼不能进行,他说罗切斯特 15 年前娶梅森先生的妹妹伯莎・梅森为妻。罗切斯特承认了这一事实,并领人们看被关在三楼的疯女人,那就是他的合法妻子。她有遗传性精神病史,就是她在罗彻斯特的房间放火,也是她撕碎简婚纱的面罩。 # 第二十七章: 简爱经历一场严峻的考验,法律阻碍了他们的爱情,使两人陷入深深的痛苦之中。 # 第二十八章: 在一个凄风苦雨之夜,简・爱悲痛欲绝地离开了桑费尔德庄园。她仅有的积蓄花光后风餐露宿,沿途乞讨,历尽磨难,最后晕倒在牧师圣约翰家门前,被圣约翰和他的两个妹妹救了。 # 第二十九章: 简爱睡了三天三夜,终于清醒了过来,在圣约翰家人的照料下,渐渐恢复体力。简・爱被圣约翰收留并为她谋了一个乡村教师的职位。 # 第三十章: 简爱渐渐熟悉了这里的一切。不久,简得知叔父去世并给她留下一笔遗产,同时还发现圣・约翰是她的表兄,简决定将财产平分。 # 三十一章: 一座山村农舍成了简的家,她有二十名学生,其中能识字的只有三个,能写和算的一个也没有。简的责任就是要培育这种萌芽。黄昏时,简边望着日落的景象,一边自我安慰,这时候,圣约翰・里弗斯来了,询问简对第一天工作的感觉。 # 三十二章: 简爱全心全意忠实地做乡村女教师的工作,渐渐成了那一带乡亲们喜欢的人,那段日子,简爱表面上很平静,但常常在梦中遇到罗伯斯特先生,心里焦躁不安。 # 三十三章: 圣约翰是个狂热的教徒,准备去印度传教,临行前向简・爱求婚,但他坦率地告诉她,他要娶她并不是因为爱她,而是他需要一个很有教养的助手。 # 三十四章: 简・爱觉得应该报答他的恩情,但迟迟不肯答应他。当夜,圣约翰在荒原上等待简・爱的答复,就在简・爱要作出决定的时候,她仿佛听到罗彻斯特在遥远的地方呼喊她的名字...... # 三十五章: 圣约翰非常自信简爱会追随他,并不断地做出各种努力帮助简爱尽快下定决心与他结婚。简爱在圣师的感召下差点失去了抗争的勇气,在那一刻,简爱又感受到内心有一种声音在不断地呼唤她,使简爱无法抗拒,简爱明白自己应该如何选择了。 # 三十六章: 心灵有所感应的简爱赶回到桑菲尔德庄园,那座宅子已成废墟,得知疯女人放火后坠楼身亡,罗切斯特也受伤致残,孤独地生活在几英里外的一个农场里。 # 三十七章: 简・爱终于找到了罗伯斯特先生并大受震动,和他结了婚,得到了自己理想的幸福生活。 # 三十八章: 两年之后,罗切斯特治好了一只眼睛,他看到了简・爱为他生的第一个孩子。 # 赏析: 这是一部以爱情为主题的小说,主人公简・爱是一个心地善良,善于思考的女性,她生活在社会的最低层,受尽磨难。她的生活草鱼令人同情,但她那倔强的性格和勇于追求平等幸福的精神更令人人们所赞赏。 在里德太太家,10 岁的简面对舅母,表兄的歧视和虐待,已经表现出强烈的反抗情绪。在她的表兄殴打她的时候,她勇于回击,当舅母叫自己的孩子远离她的时候,她个、高喊 “他们不配和我在一起”,当她被囚禁在空房中的时候,想到自己所受的虐待,从内心发出了 “不公正” 的呐喊。在孤儿院,简的反抗性格更为鲜明,这和她的朋友海伦・朋斯忍耐顺从的性格形成了鲜明的对比。海伦・朋斯虽然遭受迫害却信奉 “爱你的仇人”,在宗教的麻痹下,没有仇恨,只有逆来顺受。而简对冷酷的校长和摧残她们的教师深恶痛绝。她对海伦说:“如果她用那根条子打我,我要从她手中夺过来,并且当面折断它。” 这充分表露了她的不甘和不向命运妥协的倔强性格。 小说主要描写了简・爱与罗契斯特的爱情。简・爱的爱情观更加深化了她的个性。他认为爱情应该建立在平等基础上,而不应该取决于社会地位,财富和外貌上。只有男女相方能彼此相爱,这样才能得到真正的爱情。在追求个人的幸福时,简・爱表现出了异乎寻常的纯真,朴实的思想感情和一往无前的勇气。她并没有因为自己的仆人地位而放弃对幸福的追求,她的爱情是纯洁高尚的,她对罗契斯特的财富不屑一顾。她之所以钟情于他,只是因为他能平等待人。把她视为朋友,与她坦诚相见。对罗契斯特来说,简・爱犹如一股清新的风,使他精神为之一振。罗契斯特过去看惯了上层社会的冷酷和虚伪,简・爱的纯朴,善良和独立的个性重新唤起他对生活的追求和向往。因而他能真诚地在简面前表达他的善良的愿望和改过的决心。简爱是一部具有浓厚浪漫现实主义小说,整部作品以自叙形式写成。大量运用了心理描写是小说的一大特色。全书构思精巧,情节波澜起伏,给读者制造出一种阴森恐怖的气氛,而又不脱离一个中产阶级家庭的背景。作者还以行情的笔法描写了主人公之间的真挚爱情和自然风情,感情色彩丰富而强烈。这部优美,动人并带有神秘色彩的小说,至今仍保持着它独特的艺术魅力。

2022/12/19
articleCard.readMore

初中历史纪年表(超级完整)

一键下载所有图片(ZIP) 一键下载所有图片(ZIP) 图片转载于初中历史大事年表 - 豆丁网 (docin.com),侵删。

2022/9/21
articleCard.readMore

初中世界历史年代尺(大事年表)

一键下载所有图片(7Z) 一键下载所有图片(7Z) 图片转载于 (完整版) 初中世界历史年代尺 (大事年表) - 豆丁网 (docin.com),侵删。

2022/9/21
articleCard.readMore

《聊斋志异》译文与赏析

# 卷一 # 瞳人语 # 译文 (转自 --- 瞳人语_百度百科 (baidu.com)) 书生方栋,在长安城里很有点名气,但他为人很轻佻,不守礼节。每在郊外遇到游玩的女子,就很不礼貌地尾随在后头。 清明节的前一天,他偶然到城郊游玩,见到一辆小车子,挂着朱红色的穸帘,周着绣花簇锦的车帷,几位女婢骑着马跟在车后。其中一个婢女,骑着匹小马,容貌美丽极了。方栋稍向前凑近,偷眼一看,见车的帷幔拉开着,车里坐着一位十五六岁的女郎,她妆梳非常艳丽,真是生平从未见到过。方栋目光缭乱,神志昏昏,跟在车的前前后后,舍不得离开,这样跟着走了好几里。忽听车中女郎把婢女叫到车边,说:“给我把帘子放下来。哪里来的这么一个狂妄书生,频频地来偷看。” 婢女把穸帘放下,回过头愤怒地看着方栋说:“这是芙蓉城里七郎的新娘回娘家,不是一个乡下女子,随便让秀才偷看的。” 说完,就从车道上抓起一把土,朝着方栋扬去。 方栋眯眼睁不开,刚刚用手擦试眼睛,女郎的车马已经远去了。他惊恐疑惑地回到家里,总觉得眼睛里不舒服。请人扒开眼睑一看,眼球上生出了一层薄膜。过了一宿,越发严重,眼泪不止地簌簌流下来。白色的翳膜渐渐大起来,又过了几天,就像个铜钱那么厚。右边的那个眼球上,起了如同螺旋状的厚翳膜,用各种药物医治,都不见效。这时,方栋心中懊悔极了,很愧悔自己作法不当。他听说佛家的《光明经》能消除灾难,就手拿一卷,请别人教诵。最初,读时心情很烦躁,时间久了,渐渐地就习惯了。一天早晚无别的事可作,只盘腿坐着捻珠诵经。就这样他持续了一年,什么杂乱的念头也没有了。忽然,听到左边眼睛中,有如小蝇的声音,说:“黑如漆,真难受死了。” 右边眼睛中应声说:“可以一同出去游玩一会儿,出出这口闷气。” 方栋渐渐觉得两鼻孔中,蠕蠕动弹,很痒,好像有东西从鼻孔里面爬出来。过了一段时间,又返回来,又从鼻孔进到眼眶里。它们又说:“好长时间没能看看园中的亭台了,那珍珠兰快要枯死了。” 方栋生平很喜欢兰花,园中种植了许多兰花,以前自己常去灌水,自从两眼失明,长久没再过问。忽然听到这话,急忙问他的妻子:“兰花怎么弄得快干死了?” 妻子问方栋怎么知道的,方栋就把实情告诉妻子。妻子到花园中一看,果然兰花枯萎了。妻子感到惊异,静静躲在屋里看个究竟,见有小人从方栋的鼻子中出来,大小不如一粒豆子,转转悠悠地竟到门外去了,越走越远,接着就看不清了。一会儿,两个小人又挎着胳膊回来,飞到方栋的脸上,好像蜜蜂和蚂蚁回窝一样。就这样倒腾了二三天。 方栋又听左眼中小人说:“这条隧道弯弯曲曲,来来去去很是不方便,还不如自己另开一个门。” 右眼睛中小人说:“我这里的洞壁太厚,要开门不太容易。” 左边的说:“我来试试看,若能开开,咱俩就住到一块算了。” 方栋接着感到左眼眶内隐隐地痛似抓裂一样。一会,睁开眼一看,突然屋里的桌椅等物看得很清楚。方栋很高兴地告诉妻子。妻子仔细查看,左眼中那层小脂膜破开一个小孔,露出亮晶晶的黑色眼球,才有半个胡椒粒那么大。过了一宿,那层翳膜全消退了。细细一看,竟然是两个瞳人。而右眼厚厚的翳膜,仍是老样子,这才知两个瞳人合居在一个眼眶里了。方栋虽然瞎了一只眼睛,但比以前两个眼睛时看东西更清楚。自这以后,他对自己的行为,就更检点约束了,乡亲们都称赞他的品德好。 异史氏说:乡里有个士人,和两个朋友一起出去,途中看见一个少妇骑着毛驴出现 在他前头。戏谑的说道:“有美人啊!” 回头看了看两个朋友说:“追她!” 三人于是笑着跟从。等到追上一看,是他的儿媳。心里很羞愧丧气,不再说话。朋友假装不知道,评头论足十分猥亵。士人很尴尬忸怩,支支吾吾的说:“这是我长子媳妇啊!” 于是各自偷笑而止。轻薄的人往往自取其辱,真是很可笑啊!至于双眼被迷失明,又是鬼神的惨痛报应啊。芙蓉城主,不知道是何处神祇,难道不是菩萨现身吗?眼睛里的小瞳人,应是劈开一个小门,犯了错误,鬼神纵然凶恶,又何尝不允许别人改过自新呢! # 解析 (转自 --- 聊聊斋,谈谈心 之《瞳人语》 - 简书 (jianshu.com)) 这个故事大概说的是方栋这个浪子生性喜欢调戏美人,本来窈窕淑女,君子好逑嘛,但是在清明前一天却调戏错了对象,调戏了芙蓉城七郎子新妇,被惩罚了双眼生翳,右眼还起旋螺瞎了,而左眼成了双瞳。从此方栋浪子回头,变老实了,不再玩火,不再好色了。 中国封建时期,等级制度特别讲究三纲五常,而三纲是指 “君为臣纲”、“父为子纲”、“夫为妻纲”。侍君如侍父,同样弑君如弑父,古时会经常称地方官为父母官,这就意味着君与臣、官与民之间是存在和父与子之间的一样的乱伦禁忌。就像文中那婢说 “此芙蓉城七郎子新妇归宁,非同田舍娘子,放教秀才胡觑!(这是芙蓉城主七儿子新娶的老婆回娘家,不是普通的村姑,你这穷秀才瞅啥!)”。且不说芙蓉城主是何方神仙,城主本来就是一城的父母官,父母官的儿媳妇当然是不能乱瞅的,不像村姑那样可以随便被调戏。方栋要受到的惩戒不是一般的长针眼,而要长翳,甚至起旋螺瞎了。但这也幸亏方栋只是用眼来 “欣赏”,没有上升到言语上的挑逗,才不会在清明时节丢了性命到地狱里受罚。 古时的男性在俄底浦斯期都很难过得好,因为古时男性在俄期要处理的依然是二元关系,只是从之前的母子关系转移到了父子关系,而不是真正处理孩子、爸爸、妈妈的三元关系,这就会造成了古时男性面对女性时,总是在有着面对自己对妈妈的渴望,只要敢有任何猥琐的想法,内心会受到无意识中的古时乱伦禁忌惩罚。就好像文中方栋敢去窥视城主的儿媳妇,受到的惩罚是眼睛不能乱瞅,在方栋痛定思痛之后,左眼在意象中是象征着和爸爸的关系,变成了双瞳,意味着更加看清楚和遵守父性的权威,整个人变得更老实了,而右眼在意象中会是象征和妈妈的关系,起旋螺,变瞎了,意味着自己内心对于妈妈的任何企图都只能放在心深处,把兴趣转移到了自己的 “后花园”—— 妻子身上。 不过,古人还是知道事情不能做得太绝了,老爸不能去抢儿子女人,一来显得太低能了,要去和儿子抢吃的,二来免得把儿子逼上绝路,儿子会造反的,就像文后的士人看到美人是自己的 “长男妇”,就变得垂头丧气。同时古时男性特别是有些文化的人,其实是有一定身份的人了,会在外面表现出风流成性,放荡不羁是时尚,他们是可以去调戏一下村姑或者青楼女子,满足或者发泄自己内心的性冲动,但却不敢真正去追求女性,更别说敢去接触父母官家里的女人,而婚姻永远是 “父母之命,媒妁之言”,自己能拥有的老婆只能是父母认可的。 在精神分析当中会称乱伦禁忌或者冲动为俄底浦斯情结,翻译成大白话就是儿子要把爸爸干掉,就是为了抢老爸的女人,也就是妈妈来满足自己需求。当然这事情往往是不能成功的,儿子最终只能清醒地意识到,妈妈永远只能是爸爸的女人,是自己的妈妈,自己可以拥有真正属于自己的女人是需要在外面找,从而把自己的目光转移到了别的女人身上来满足自己性需求或者自己战胜了爸爸的幻想。 但如果妈妈和儿子的连接太紧密的话,也就是儿子太过粘妈妈的话,儿子在俄期发现自己无法和爸爸抗衡后只是从这竞争关系中表面地撤退,但不代表儿子会放弃妈妈可以是自己女人的想法。儿子会无意识地不断去寻找不同女性,或者在别的女人身上寻找妈妈的影子,把别的女人当成自己妈妈来对待要求,或者用各种各样的方式继续待在妈妈身边和妈妈保持连接比如长大了依然待在家里啃老之类,这样只会对孩子的成长带来不利的影响,一直陷在了过去情结当中,无法走出来拥有自己的真正人生。 # 王六郎 # 译文 (转自 --- 王六郎(清代蒲松龄创作的文言短篇小说)_百度百科 (baidu.com)) 有个姓许的,家住淄川县城北,以打鱼为生。他每天傍晚总要带酒到河边去,边喝酒边打鱼。而喝酒前,又总是先斟上一盅祭奠一下,并祷告说:“河中的溺鬼,请来喝酒吧!” 这样便习以为常。其他人往往打鱼很少,而他每天都打满筐的鱼。一天傍晚,许某刚刚独自饮酒,见一少年走来,在他身边转来转去。许某让他同饮,少年也不推辞,二人便对饮起来。这一夜竟连一条鱼也未能打到,许某很有些丧气。少年起立躬身说:“我到下游为你赶鱼。” 说罢,朝下游飘然走去。一会儿,少年回来说:“大群鱼来了!” 果然听到有许多鱼吞吃饵食的声音。许某便撒网,一网捕了十数尾尺把长的大鱼。他非常高兴,对少年深表感谢。少年欲走,许送鱼给他,少年不要,并说:“屡次喝你的好酒,这点小事怎能提到感谢呢?如您不嫌麻烦,我将常来找您。” 许某说:“才相见一晚,怎说多次?你如愿来相助,我是求之不得,可我怎样报答你的情意呢?” 于是便问少年姓名。少年说:“我姓王,没有名字,你见面就叫我王六郎吧。” 说罢,便告辞而去。次日,许某将鱼卖掉,顺便多买了些酒。当晚,许某来到河边时,六郎早已先在等候,二人便开怀畅饮。饮几杯后,六郎便为许某赶鱼。 就这样半年过去了。一天,六郎忽然对许说:“你我相识,情同手足,可是,咱们马上就要分别了。” 说得很是悲伤。许某甚为诧异,问六郎为何这样,六郎考虑再三,才说:“你我既然亲如兄弟,我说了你也不必惊讶。如今将要分别,无妨如实告知:我实际是一鬼,只因生前饮酒过量,醉后溺水而死,已经好几年了。以前你之所以捕到比别人更多的鱼,都是我暗中帮你驱赶,以此来酬谢奠酒之情。明 日我的期限已满,将有人来代替我,我将要投生于人间,你我相聚只有今晚了,所以我不能平静。” 许某听了起初十分害怕,然而,因为长期相处,不再恐怖,反而难过起来。于是,他满满斟了一杯酒捧在手中说:“六郎,我敬你这杯酒!望你饮了不要难过。你我从此不能相见,虽很伤心,但你由此解脱灾难,我应该祝贺你。不要悲伤,应该高兴才是!” 于是,二人继续畅饮。许问六郎:“何人来相替?” 六郎说:“兄长明 日可在河边阴处等候,正当午时,有一女子渡河,溺水而死,即是替我之人。” 二人听到村鸡鸣叫,方洒泪而别。次日,许在河边暗暗观看,会发生什么事情。中午时,果有一怀抱婴儿的妇女,到河边便坠入水中。婴儿被抛在岸上,举手蹬脚地啼哭。妇女几次浮上沉下,后竟又水淋淋地爬上河岸,坐在地上稍稍休息后,抱起婴儿走了。当许某看到妇女掉入水中时,很不忍心,想去相救,但一想这是六郎的替身,才打消救人的念头。当又看到妇人未溺死,心中怀疑六郎所言有些荒唐。当晚,许某仍到原地去打鱼,而六郎早已在那里,说:“如今又相聚了,可暂先不说分别的事。” 许某问六郎白天的事,六郎说:“本来那女子是替我的,但我怜她怀中婴儿,不忍心为了自己一人而伤两个人的性命。因此,我决定舍弃这个机会,但又不知何时再有替死的人。也许是你我缘分未尽啊。” 许某慨叹地说:“你这种仁慈之心,总可感动玉帝的。” 从此,二人一如既往,饮酒捕鱼。过了几天,六郎又来向许某告别,许以为又有替六郎之人。六郎说:“不是的,我前次之好心果然感动了玉帝,因而招我为招远县邬镇的土地神。明日要去赴任,如你不忘咱俩的交情,不要嫌路远,去招远看我。” 许某祝贺说:“贤弟行为正直而做了神,我感到十分欣慰。但人和神之间相隔遥远,即使我不怕路远,又怎样才能见到你呢?” 六郎说:“只管前往,不要顾虑。” 再三嘱咐而去。 许某回到家,便要置办行装东下招远。他妻子笑着说:“这一去几百里路,即使有这个地方,恐怕和一个泥塑偶像也无法交谈。” 许某不听,终究去了招远。问当地居民,果然有个邬镇。他找到了邬镇,便住进一个客店,向主人打听土地祠在什么地方。主人惊异地说:“客人莫非姓许?” 许某说:“是的,但是您怎么知道?” 店主人又问:“客人莫非是淄川人?” 许某说:“是的,然则您又是怎么知道的?” 店主人并不回答,很快地走出去。过了一会,只见丈夫抱着小儿,大姑娘小媳妇在门外偷看,村里人纷纷到来,围看许某,如四面围墙一般。许某更为惊异。大家告诉他说:“前几夜,梦见神人来告知:有一个淄川姓许的人将来此地,可以给些资助。因而在此等候多时。” 许某甚为奇怪,便到土地祠祭祀六郎,祷告说:“自从与你分别后,睡梦中都铭记在心,为此远道而来赴昔日之约。又蒙你托梦告知村里人,心中十分感谢。很惭愧我没有厚礼可赠,只有一杯薄酒,如不嫌弃,当如过去在河边那样对饮一番。” 祷告毕,又烧了些纸钱。顷刻见到一阵旋风起于神座之后,旋转许久才散去。当夜,许某梦到六郎来到,衣冠楚楚的,与过去大不相同。六郎致谢道:“有劳你远道而来看望我,使我又欢喜又悲伤。但我如今有职务在身,不便与你相会,近在咫尺,却如远隔山河,心中十分凄怆。村中人有微薄的礼物相赠,就算代我酬谢一下旧日的好友。当你回去的时候,我必来相送。” 许某住了几天,打算回家,大家殷勤挽留,每天早晚都轮流作东道主为许某饯行。许坚决告辞,村中人争着送来许多礼物,为他充实行装。不到一天,送的礼物装满行囊,男女老少都聚集来送许出村。忽然刮起一阵旋风,跟随许某十馀里路。许对着旋风再拜说:“六郎珍重,不要远送了。你心怀仁爱,自然能为一方百姓造福,无需老朋友嘱咐了。” 旋风又盘旋许久,才离去。村中的人也都嗟叹着返回了。许某回到家里,家境稍稍宽裕些,便不再打鱼了。后来见到招远的人,向他们打听土地的情况,据说灵验得像传说的那样,远近闻名。 异史氏说:“王六郎身在青云之中当神,还不忘记贫贱时的朋友,这就是他所以神异的原因。今 日坐在车里面的显贵,难道还认识那个戴着斗笠的人吗?我的乡里有一个退休了的人,家里非常贫穷。他有一个年小的时候就交往的朋友,如今做了显贵。他想要是投奔他去一定会得到周济照顾。于是竭尽全力置办行装,奔波了上千里路,结果非常失望的回来;他花光了行囊里所有的钱财并卖掉了坐骑,才能够回来。他的族弟是个很诙谐的人,作了一首《月令》来嘲讽这件事说:‘这个月,哥哥回来了,貂皮帽子也解下来了,车马伞盖也没有张开来,马也变成驴了,靴子这才没了声音。’念一下这个可以笑一笑。” # 解析 (转自 --- 王六郎人物分析,主题,现实意义,高中语文,聊斋_百度知道 (baidu.com)) # 人物分析: 因为渔夫经常 “饮则酹地”。所以王六郎要报答渔夫,使得 “他人渔,迄无所获,而许独满筐”。表现了他的知恩图报,重情义的性格特点。 集中体现在王六郎放弃妇人代死这一部分。“果有妇人抱婴儿来,及河而堕。儿抛岸上,扬手掷足而啼。妇沉浮者屡矣,忽淋淋攀岸以出,藉地少息,抱儿径去。” 在亭午时分,一名妇人怀抱婴儿前来,行至河畔,旋即失足坠入河中,在该妇人载沉载浮的奋力挣扎中,伴随着河岸幼儿扬手掷足的高声哭啼。结果是妇人没有沉下去,而是 “忽淋淋攀岸以出”,抱着儿子回去了。 当晚,二人照常来到河边聚会。渔夫向他询问了这件怪事。王六郎回答说:“女子已相代矣;仆怜其抱中儿,代弟一人遂残二命,故舍之。” 作为一个溺死鬼,当有人做替身时,自己本可以投胎复生,重新做人,然而在这 “生死攸关”,他却甘愿放弃这个机会,而是把机会让给更需要生命的人 —— 手抱婴儿的妇女。这个故事的寓意是:人和鬼之间,只要讲诚信,也可以成为知己; # 主题: # 知恩图报,有情有义。 # 舍己救人、善良高尚。 # 现实意义: 人和人之间,也应该注重诚信。 # 种梨 # 译文 (转自 --- 种梨(清代小说家蒲松龄创作的文言短篇小说)_百度百科 (baidu.com)) 有个乡下人,在集市上卖梨。梨的味道非常香甜,但价钱很贵。有个道士,戴着破道士帽,穿着破烂道袍,在车前伸手向乡下人乞讨。乡下人呵斥他,他也不走。乡下人生气了,大声地辱骂起来。道士说:“你这一车梨有好几百个,贫道只讨你一个,对你来说没多大损失,为什么还要发这么大的脾气呢?” 观看的人劝乡下人拿一个不好的梨给老道士,打发他走算了,乡下人坚决不肯。 路旁店铺里的一个伙计,见他们吵得不成样子,就拿出钱买了一个梨,给了道士。道士拜谢,然后对着众人说:“出家人不知道吝惜东西。我有好梨,请大家品尝。” 有人问:“你既然有梨,为什么不吃自己的?” 道士说:“我是需要这个梨核做种子。” 于是捧着梨大口大口地吃了起来。道士吃完梨,把核放在手里,取下背在肩上的小铁铲,在地上挖了个几寸深的坑,然后放进梨核,盖上土,向旁边的人要点热水浇灌。有好事的人便到路边店铺中提来一壶滚开的水,道士接过开水浇进了坑里。大家都瞪着眼看着,见一棵嫩芽儿冒了出来,并渐渐长大,一会儿就长成了一棵枝繁叶茂的大树;转眼间开花、结果,又大又香的梨子挂满了枝头。道士从树上摘下梨子,分给围观的人吃,一会儿功夫就吃光了。然后,道士就用铁铲砍树,叮叮当当地砍了好长时间方才砍断。道士把满带枝叶的梨树扛在肩上,不慌不忙地走了。 一开始,道士做戏法时,那个乡下人也杂在人群中,伸着脖子瞪着眼看,竟忘记了自己的营生。道士走了以后,他才回来去看顾他车上的梨,却已经一个也没有了。他这才恍然大悟,道士刚才分的梨子都是他的;再细细一看,一根车把没有了,碴口是新砍断的。乡下人心里非常气愤,急忙去追赶道士。转过一个墙角,见砍断的车把扔在墙角下,这才知道道士刚才砍的那棵梨树,就是他的车把,而道士却已经不知去向了。满集市上的人都笑得合不上嘴。 异史氏评论:“乡人烦闷昏庸的样子,憨状可掬,十分痴傻,他受市人嘲笑,也是有道理的。我每每见到乡中富人,至亲好友向他乞米求助,就表现出一副气愤的样子,就计较说:‘(这)是好几天的物资开支了。’ 如果劝他救济危难的人,给孤独无靠的人饭吃,则又忿然,又计较说:‘这是十个人、五个人的饭量。’ 甚至连父子兄弟,也极微细的钱财也要彻底计较。(但是)一旦关乎荒淫烂赌,则整个囊袋家产也不吝啬;刀锯架在头颈上,连赎命也来不及。诸如此类的事,正是说之不尽;而(相对而言)愚蠢的乡下人的做法,又有什么值得奇怪的呢?” # 赏析 (转自 --- 种梨(清代小说家蒲松龄创作的文言短篇小说)_百度百科 (baidu.com)) 《种梨》所讲的故事只是一个风趣剧,轻松而幽默。说的是一个村夫在集市上卖梨,而一个道人万端乞讨而不得。其间一个伙计实在看不下去了,就买了一个送给道人,没想到道人吃毕,把核种于地下,霎时间便生芽、发展、开花、结果,于是道人遍送观者。而村夫待道人走后发现本身的一车梨已经子虚乌有,才突然觉悟大悟。然而,蒲松龄先生却在评价中说道:"良友…… 父子兄弟,较尽锱铢。及至淫博迷心,则顷囊不吝;刀锯临颈,则赎命不遑。诸如此类,正不胜道……" 其极重繁重和愤慨,使人足见先生对吝啬者之恨了。 # 劳山道士 # 译文 (转自 --- 崂山道士(《聊斋志异》篇目)_百度百科 (baidu.com)) 县里有个姓王的书生,排行第七,是官宦之家的子弟,从小就羡慕道术。他听说崂山上仙人很多,就背上行李,前去寻仙访道。他登上一座山顶,看见一所道观,环境非常幽静。有一个道士坐在蒲团上,白头发垂到脖颈上,神情相貌清爽高超。王生上前见过礼并与他交谈起来,觉得道士讲的道理非常玄妙。便请求道士收他为徒,道士说:“恐怕你娇气懒惰惯了,不能吃苦。” 王生回答说:“我能吃苦。” 道士的徒弟很多,傍晚的时候都集拢来了。王生一一向他们行过见面礼,就留在道观中。 第二天凌晨,道士把王生叫去,交给他一把斧头,让他随众道徒一起去砍柴。王生恭恭敬敬地答应了。过了一个月,王生的手脚都磨出了厚厚的老茧,他再也忍受不了这样的苦累,暗暗产生了回家的念头。 有一天傍晚,他回到观里,看见两个客人与师傅共坐饮酒。天已经晚了,还没有点上蜡烛。师傅就剪了一张像镜子形状的纸,贴在墙上。一会儿,那纸变成一轮明月照亮室内,光芒四射。各位弟子都在周围奔走侍候一个客人说:“良宵美景,其乐无穷,不能不共同享受。” 于是,从桌上拿起酒壶,把酒分赏给众弟子,并且嘱咐可以尽情地畅饮。王生心里想,七八个人,一壶酒怎么能够喝?于是,各人寻杯觅碗,争先抢喝,惟恐壶里的酒干了。然而众人往来不断地倒,那壶里的酒竟一点儿也不少。王生心里非常纳闷。过了一会儿,一个客人说:“承蒙赐给我们月光来照明,但这样饮酒还是有些寂寞,为什么不叫嫦娥来呢?” 于是就把筷子向月亮中扔去。只见一个美女,从月光中飘出,起初不到一尺,等落到地上,便和平常人一样了。她扭动纤细的腰身、秀美的颈项,翩翩地跳起 “霓裳舞”。接着唱道:“神仙啊,你回到人间,而为什么把我幽禁在广寒宫!” 那歌声清脆悠扬,美妙如同吹奏箫管。唱完歌后,盘旋着飘然而起,跳到了桌子上,大家惊奇地观望之间,已还原为筷子。师傅与两位客人开怀大笑。又一位客人说:“今晚最高兴了,然而我已经快喝醉了,二位陪伴我到月宫里喝杯饯行酒好吗?” 于是三人移动席位,渐渐进入月宫中。众弟子仰望三个人,坐在月宫中饮酒,胡须眉毛全都看得清清楚楚,就像人照在镜子里的影子一样。过了一会儿,月亮的光渐渐暗淡下来,弟子点上蜡烛来,只见道士独自坐在那里,而客人已不知去向。桌子上菜肴果核还残存在那里。那墙上的月亮,只不过是一张像镜子一样的圆的纸罢了。道士问众弟子:“喝够了吗?” 大家回答说:“够了。” 道士说:“喝够了就早去睡觉,不要耽误了明天打柴。” 众弟子答应着退了出去。王生心里惊喜羡慕,回家的念头随即打消了。 又过了一个月,王生实在忍受不了这种苦累,而道士还是连一个法术也不传授,他心里实在憋不住,就向道士辞行说:“弟子不远数百里来拜仙师学习,即使不能得到长生不老的法术,若能学习点小法术,也可安慰我求教的心情。如今过了两三个月,不过早上出去打柴,晚上回来睡觉。弟子在家中,从没吃过这种苦。” 道士笑着说:“我本来就说你不能吃苦,现果然如此。明天早晨就送你回去。” 王生说:“弟子在这里劳作了多日,请师傅稍微教我一点儿小法术,我这次来也算没白跑一趟。” 道士问:“你要求学点什么法术?王生说:“平常我见师傅所到之处,墙壁也不能阻挡,只要能学到这个法术,我就知足了。” 道士笑着答应了。于是就传授他秘诀,让他自己念完了,道士大声说:“进墙去!王生面对着墙不敢进去。道士又说:“你试着往里走。” 王生就从容地向前走,到了墙跟前,被墙挡住。道士说:“低头猛进,不要犹豫!” 王生果然离开墙数步,奔跑着冲过去,过墙时,像空虚无物;回头一看,身子果然在墙外了。王生非常高兴,回去拜谢了师傅。道士说:“回去后要洁持自爱,否则法术就不灵验。” 于是就给他些路费,打发他回去了。 王生回到家里,自己夸耀遇到了仙道,坚固的墙壁也不能阻挡他。他的妻子不相信。王生便仿效起那天的一举一动,离墙数尺,奔跑着冲去,头撞到坚硬的墙上,猛然跌倒在地。妻子扶起他来一看,额头上鼓起大包,像个大鸡蛋一样。妻子讥笑他,王生又惭愧又气愤,骂老道士没安好心。 异史氏说:听说王生这个故事的人没有不大笑的,殊不知世上的 “王生” 还真不少。现在有那么一个匹夫,喜欢别人阿谀奉承不喜欢忠言劝谏,于是那些阿谀迎奉的小人就呈上那些可以逞威扬暴的伎俩,来迎合他,并骗他说:靠着这个本事,就可以横行无阻了。一开始试验都小有灵验,于是就说天下之大,都可以像这样横行,真是一个不碰南墙不回头的人啊! # 赏析 (转自 ---《小说、戏剧・崂山道士》原文与赏析 - 中外经典 - 品诗文网 (pinshiwen.com)) 这篇小说以简洁轻快的笔调刻画出一位畏难怕苦,不求真知;浅尝辄止,轻浮健忘,学到一点皮毛就自炫自夸的王生。其结果只落得头撞南墙,一事无成,唯有头上的肿疱而已。王生的形象愈鲜明逼真,作品的讽刺意味也愈隽永深长。从而使形象的生动性和主题的深刻性,得到和谐的统一。 《崂山道士》喜趣横生,极富艺术魅力,其成功的艺术经验有四:其一,从发展中显现人物自身的矛盾。凡古今引人入胜,而耐人寻味的佳作,几乎无例外地都是再现矛盾的艺术。可以说,艺术的魅力首先是矛盾的魅力,蒲松龄的高明在于他正是矛盾的发现者、把握者和再现者。《崂山道士》情节的喜剧性来自人物的悲剧性格。王生既想学道,又不肯吃苦;既想虔诚敬道,又不肯接道长的要求去做;既想炫耀自己,又无真本事;既想讨妻子的赞赏,又无自知之明。这样小说便从王生的主观意愿和实际能力大相径庭的矛盾中,透过一定事件的考验展现出人物的个性特征,使人物形象立体化,更加有血有肉。由此可见,审美对象也包括丑,它一经审美主体的把握,例如这篇讽刺小说对于客观存在的丑的把握,也就创造了对丑的反映的艺术美。 其二,小说委婉有致地写出人物在不同情境下的各种心态。因王生自幼慕道,所以他赴数百里之外求师学道。当他刚到劳山时,见观宇 “甚幽”,道士 “神光爽迈”,便毅然拜师学道。但他从来未想过学道要付出艰辛的代价,足见王生无知。仅一个多月早出晚归的劳作他便打熬不住转念回家了,王生的心志不坚,自然不言而喻。一旦目睹了道士的真本领又想留下来,恨不得一吃成胖子,其好高鹜远的虚荣心又得以充分展现。再过上一个多月的劳苦生活,旧态复萌,又不想干了,临走前道士教以小技便心满意足了,只要装点、不求真知的浅薄心理昭然若揭。回家后,面对不懂道术的妻子,又是自我吹嘘,又是急不可待地当场表演,欺世盗名的心态和盘托出。如此,层次井然地揭示出王生在不同情境中的内在丑,从而使人物个性渐趋鲜明,作品的立意也愈加深刻。 其三,巧用漫画式的夸张手法。作者准确地把握了王生在妻子面前表演时踌躇满志的心态,神形兼备地予以适度的夸张,王生碰壁后额上 “巨卵” 格外醒目,寥寥数笔极尽揶揄嘲讽之能事,不但渲染了喜剧气氛,而且使这位玩弄小术的王生自食其果。作品的讽刺效果也就自然而微妙地得以发挥,这正是作者炉火纯青的艺术功力所致。 其四,寓深刻的哲理性于轻松的笑声之中。《崂山道士》既是讽刺小说,也是寓言故事。它具有亦庄亦谐,寓庄于谐的特点,饶有丰富的哲理性内蕴。王生既是一个具有独特性格的艺术形象,又是生活中随处可见的众生相,他那种自我吹嘘而又不自量的性格特征,必然导致碰壁的悲剧,正像篇末异史氏所言,“闻此事未有不笑者,而不知世之王生者正复不少。” 作者旨在借王生嘲讽世上所有王生的同类。古罗马贺拉修斯在他的名著 《诗艺》中说得好: “寓教于乐,既劝谕读者,又使他喜爱。”“教” 也就是某种哲理,其所以引起快感,启迪智慧,给人益处和乐趣,同时又对生活有帮助,正因为美是一种善。

2022/8/23
articleCard.readMore

《聊斋志异》简介及读后感

# 《聊斋志异》简介及读后感 # 一、《聊斋志异》简介 《聊斋志异》是蒲松龄的代表作,在他 40 岁左右已基本完成,此后不断有所增补和修改。"聊斋" 是他的书屋名称,"志" 是记述的意思,"异" 指奇异的故事。全书有短篇小说 491 篇。题材非常广泛,内容极其丰富。多数作品通过谈狐说鬼的手法,对当时社会的腐败、黑暗进行了有力批判,在一定程度上揭露了社会矛盾,表达了人民的愿望。但其中也夹杂着一些封建伦理观念和因果报应的宿命论思想。《聊斋志异》的艺术成就很高。它成功的塑造了众多的艺术典型,人物形象鲜明生动,故事情节曲折离奇,结构布局严谨巧妙,文笔简练,描写细腻,堪称中国古典短篇小说的高峰。 《聊斋志异》,是一部文言短篇小说集。有传奇、志怪、轶事等,诸体兼备,为中国文言小说集大成之作。内容十分广泛,多谈狐、魔、花、妖,以此来概括当时的社会关系,反映了 17 世纪中国的社会面貌。书中写的是一个花妖鬼狐的世界,既有对如漆墨黑的社会现实的不满,又有对怀才不遇、仕途难攀的不平;既有对贪宫污吏狼狈为奸的鞭笞,又有对勇于反抗,敢于复仇的平民的称赞;而数量最多、质量上乘、写得最美最动人的是那些人与狐妖、人与鬼神以及人与人之间的纯真爱情的篇章。 《聊斋志异》是一部具有独特思想风貌和艺术风貌的文言短篇小说集。多数小说是通过幻想的形式谈狐说鬼,但内容却深深地扎根于现实生活的土壤之中,曲折地反映了蒲松龄所生活的时代的社会矛盾和人民的思想愿望,熔铸进了作家对生活的独特的感受和认识。 # 二、从题材内容来看《聊斋志异》中的作品大致可分为以下五类: 第一类,是反映社会黑暗,揭露和抨击封建统治阶级压迫、残害人民罪行的作品,如《促织》、《红玉》、《梦狼》、《梅女》、《续黄粱》、《窦氏》等; 《聊斋志异》在进步的思想内容中也夹杂着一些落后的成分,如封建伦理道德观念,鬼神迷信和因果报应思想,追求功名利禄的庸俗倾向等,是我们阅读时应注意分析批判的。 郭沫若评价说:"写鬼写妖高人一筹,刺贫刺虐入木三分" # 三、 《聊斋》中的女性大致可分为四类 第一类,是为数最多的勇于追求爱情,对爱情忠贞不渝的忠女,烈女,豪放女们 。 如《青凤》,《婴宁》、《莲香》,《聂小倩》等。 《青凤》:女主人公青凤是一狐女,如其他聊斋女性一样 "世间无其丽",在与耿生相恋之初,她谨听叔训,"不敢奉命"。经过几番挣扎和几年痛苦的思念,在与耿生的一次意外相遇中,毅然决定离开家人的束缚与耿生共结连理。 第二类,利用智慧战胜邪恶,为家人报仇,为民除害的复仇女神。 如《商三官》,《庚娘》,《云翠仙》等。 《商三官》商三官是一个聪明美丽、有见识的女孩子。她的父亲商士禹因得罪地主史葵,被活活打死。三官立志替父报仇,于是改名换姓去戏班学戏,几年后随班子回到家乡,设法留在史家,当晚刺死了史葵。待风浪平息后,三官平安地回到家里。 第三类,是拥有远见卓识,打破封建重农抑商思想的枷锁,成为商界的女强人。 如《黄英》,《小二》等。 《小二》中 "绝贤美" 的女子赵小二就经营这样的手工作坊。她开的是琉璃厂,生产的灯样式新颖,其价格虽高,生意却出奇的好,而且她管治有方,赏罚分明,工人没有一个不服她的,丈夫只是一个工作上的帮手而已她已真正的独立不依的女人,不再是男性的附庸。 第四类,是少数几位不堪封建制度重压走向极端的泼妇。 如《马介甫》中的尹氏。 尹氏把丈夫管教得服服贴贴,无论她做什么事丈夫都是大气不敢出一口。她不仅虐待自己的丈夫,还逼得公爹出家当道士,还得弟死,侄儿差点丧命,丈夫的小妾怀孕,她动手打得 "崩注胎堕"。她固然心狠手辣,却从侧面反映男尊女卑社会对女性的摧残。 # 四、《聊斋志异》几大名篇的内容梗概 # 《画皮》:太原士子王生,在一次早晨出行的道上,遇到一个抱着包袱独自行走的女子。一问,那女子自称是不堪大妇虐待而出逃的大家小妾。王生贪恋其姿色,便将她带回家里,安置在书斋中,与其同居。妻子陈氏让他打发此女离开,王生不听,一日,王生到了集市上,一个道士吃惊地说他身上有邪气萦绕,一定是遇到了妖邪。王生不信,反以为道士是想借此混饭吃。他回到家,欲进书斋,不料门被堵上,隔着窗缝往里一看,只见一个青面狞鬼,正在描画一张人皮,随后将人皮穿在身上,又化作美女。王生非常害怕,找着道士,求他相救。道士给他一个蝇拂,让他挂在门外。王生回到家,与妻子陈氏住在一处。一更时,那化作美女的厉鬼将蝇拂弄碎,径直到床前,将王生的心摘去吃了。王生之弟二郎找来道士,将化作老妇的厉鬼治死。陈氏听从道士的指点,向一个疯癫的乞丐求救,终于将王生救活。 # 《小翠》:浙江人王太常小时候,一个比猫大的动物在雷鸣电闪时钻到他的身下。后来王太常中了进士,并做了侍御。他膝下只有一子,但是个傻子。一日一位妇人到他家,并将自己的女儿小翠留给他做儿媳。小翠聪慧过人,深得公婆喜爱,但就是整日里和健儿子疯闹。有一个官员王给谏想诬告王侍御,小翠扮成宰相亲临王侍御家,让王给谏看到,从此收起了诬告王侍御的恶念。一次王给谏到了王侍御家,看到傻儿子扮成皇帝模样,王给谏到了朝上告了王侍御谋反之罪。皇上验明不过是疯儿傻媳的玩闹后,反倒将王给谏发配充军。王侍御觉出小翠不是寻常之人。一日傻公子洗澡,小翠趁势捂死了他。等公子又活过来后,傻病全好了。过了一年,王侍御被王给谏的同党参奏被罢了官。他准备拿一只玉瓶送给朝廷的人,好给自己找路子。谁知玉瓶被小翠打碎了,公婆二人将小翠一顿大骂。小翠不堪忍受公婆的辱骂,决定离开王侍御家。临走时告诉丈夫,说自己是狐狸,母亲因避雷灾曾受过王侍御的庇护,送自己来报恩。小翠走后公子痛哭欲死,王公夫妇也知自己铸成大错,追悔莫及。两年后公子偶然又遇到小翠。但小翠不愿再回他的家。和公子在外国生活了一段时间后,小翠的模样渐渐变了。小翠为公子找了个于家姑娘为妻,自己便消失了。婚后公子发现于家女儿就是小翠的模样,方才知道小翠模样变化的原因。她将自己变成于家姑娘的模样,为的是公子见到于家女儿就像见到她,以解公子对她的思念之情。 # 《青凤》:故事的发展大约可以分为四个阶段。首先是耿去病初会青凤,一见钟情;第二,次夜相见,互诉衷情,不料被青凤的叔叔撞破,不欢而散;第三层写第二年清明耿去病上坟,得一狐,提抱以归,则青凤也,于是同居,生活得很幸福。最后写两年以后青凤的叔叔遭横难,耿去病挺身救之,"由此如家人父子,无复猜忌矣"。故事首尾完具,曲尽其妙。在封建社会里,像这样曾经遭到家长反对后来终于得到谅解的恋爱和婚姻,有是有的,比较少见,但有狐狸精的介入,事情就好办一些了。 # 《促织》:国内风行都促织,皇帝也喜欢,于是官府把上交促织作为任务摊派下去。成名(主人公)也被摊派。官府要求的促织规定很高,成名一时做不到合乎规格的促织,非常着急。于是他老婆就去一个巫神那里问卜。巫神给了她一幅画,上面画的野外的一座荒房什么的。成名觉得是指点捕捉促织的地点,就按图索骥,结果抓到一只非常好的促织,他很高兴,就把促织放起来,准备第二天交上去。结果他的小儿子,偷偷拿这只促织和别的小孩去玩,让促织跑了。儿子知道这只促织对父亲的意义,所以非常害怕,就跳井自杀了。被人们就上来后,没有死掉,在昏迷中,儿子就变成一只小小的促织。虽然这只促织很小,但也没有办法,成名也还是把它交了上去。谁知道,这只小促织凶猛异常,胜过了所有的优等促织,甚至还咬破了公鸡的鸡冠。完成任务后,儿子也醒了过来。 # 《席方平》:明朝末年,河南监察御史席廉赈灾济民,遭贪官秦士禄诬陷,被朝廷斩首。其子席方平在古庙内为父亲守灵时,半夜看到一妙龄少女出现在他面前。原来,此女名小谢,出身于书香门第,被洛阳知府看中要纳为小妾,她万般无奈只得以死抗争,化作冤魂,在她欲向巡抚秦士禄申冤时,却看到秦正在徇私枉法,贿赂钦差。而这正是陷害席方平之父的一幕。小谢得知席方平的遭遇,同病相怜,决心帮助他为父申冤。她带着席方平到阴曹地府去击鼓鸣冤,不料,判官、城隍、冥王等都是收到贿赂的贪官,他们不问青红皂白,对席方平施以火床烙身、利锯锯身等酷刑,施刑的鬼役同情席方平,手下留情,没有锯到他的心脏,才使他免于一死。气愤之中,小谢带他到天庭告状,仙界二郎神深受感动,为他主持正义,使大明皇帝了解了事实真相,惩治了贪官污吏。席方平终于为父申冤昭雪。在这生死磨练中,席方平与小谢两人产生了爱慕之情,小谢也得以借尸还魂,与席方平结成眷属。 # 《梦狼》"官虎吏狼" 白甲在外边做官,他的父亲白翁(白老头)挂念他。丁某,也就是能在阳间阴间来回走的人,带了白翁到白甲官衙,白翁先看到官衙门口有一头巨大的狼看门,吓得不敢进,丁某硬把他拉进去,白翁又看到官衙里到处都是狼,官衙的白骨已经堆成山。白甲看到父亲来了,很高兴,下令备饭,马上,有一头巨狼叼了一个人来。白翁吓得浑身发抖,问:这是做什么呀?白甲平淡地回答 "用来当饭吃。" 白翁很害怕,辞别了儿子就走,一群狼却挡住他不让走。 白翁正在进退两难时,突然来了两个怒目圆睁的金甲猛士,金甲猛士捉住白甲,白甲扑地化成了巨齿獠牙的猛虎。一个金甲猛士要砍掉白甲的脑袋,另一个说,不着急,这是明年的事,先把他的牙敲了。白翁醒后写了封信,劝导白甲要廉政爱民,派小儿子到白甲那儿看看。小儿子到了白甲的官衙,发现哥哥的门牙全掉了,问:怎么回事?白甲说骑马摔的。再问,什么时间摔的?恰好是白翁做梦的那天。小儿子把父亲的信拿出来给白甲看,苦口婆心地劝告他。白甲不听。 弟弟在官衙住了几天,发现行贿的人络绎不绝。官衙的人都在搜刮民脂民膏。弟弟流着眼泪劝告哥哥不要这样,要爱护老百姓,白甲不以为然地说:"你是个乡下人,不知道做官有做官的妙诀,一个人能不能提拔,不决定于老百姓,而决定于上司。" 没过多久,白甲升了大官,可是在他赴任的路上,一群老百姓把他杀了。过了一会,有人把白甲救起,说这个人是白老头的儿子,老头还不坏,不应该让他看到这惨状,把这人的脑袋给接上。但是把脑袋反着安上。 白甲复活后,脑袋朝后,眼睛能看到自己的背,大家都不把他当人看待。让人自顾其后,是个意味深长的细节。 # 《梦狼》是带象征意味的小说,县令化成吃人猛虎,衙役是一群恶狼,官衙以人为食,吃得白骨如山,比喻官场对百姓敲骨吸髓。"官虎吏狼" 成为揭露封建社会黑暗现实的经典性概括。 # 《武技》:幼得名师指点,学成一身武技,自诩天下难对的武生,想不到败在一卖艺女尼的五指之下,股骨差点被削断。 # 《胭脂》说的是一个怀春美人胭脂,在女友王氏怂恿下,意图与意中人鄂生幽会。却想不到王氏之情人宿介早已垂涎胭脂,夜晚竟冒充鄂生赴约,幸胭脂不愿苟合,宿介只抢得胭脂一只绣鞋就又到王氏住处,可不料想鞋子竟掉在女友家窗外,恰巧被屠户毛大拣去。毛大在窗下偷听了宿介自述的经过,几天后,翻墙入胭脂家,但由于门户不熟悉,误入胭脂父亲房间,胭脂父亲发现后持刀来捉却反而被毛大杀死,毛大在慌忙逃脱时将鞋子遗留在现场。这样胭脂认为是鄂生杀了父亲,告到官府,官府昏庸,以鞋为证,将鄂生抓来并屈打成招,定成死罪。后来上级复案时,调看犯人,觉得鄂生不像杀人犯,起疑,便追问胭脂女友 —— 王氏,才追出宿介曾冒充前来,就抓来宿介,又屈打成招,定成死罪,人们也称赞这位上司神明。可是宿介虽然放荡,但颇有文才,就向省府学官(自己老师)写了封申诉信。学官看了觉得确有疑点,就请示主管重审,又追查鞋子问题,认定拾鞋人最可疑,于是设谋定计,捉到毛大,案情才真相大白。真凶伏法,鄂生、胭脂也终成眷属。 # 《田七郎》,说一位豪爽乡绅结交了很多朋友,一天夜里,梦见有人对他说:你现在这些朋友,都不理想,只有 田七郎 才值得你交。他醒来就寻找田七郎,知道七郎是个穷猎人。多次登门拜访,为田母斥责,不愿他俩亲近。后来田七郎为猎豹与人发生争执,失手杀了人,被抓进监狱,这乡绅花了很多钱救出了田七郎,以后交往,田母也不再阻拦。一天乡绅家佣人调戏主人儿媳后逃到乡绅仇人家,并造谣说儿媳与之私通。乡绅气极,但无奈,想找田七郎商议,田七郎也不见了,乡绅很奇怪。可是不久,听说那坏佣人被人杀了,抛尸荒野。乡绅估计是田七郎干的,派人到家找他也找不到。乡绅仇人勾结官吏,抓了乡绅,而此时乡绅的朋友都散了,谁也不来帮忙伸冤。一天县官正在和乡绅的仇人一起谈事,突然来了个担柴人冲上大堂,抽刀杀了乡绅仇人。县官乱中躲开了,这人找不到县官就自刎而死。可是当县官出来验看凶手尸体时,这尸体突然跳起,一刀砍下县官的头,这才又倒下了。这杀人者正是田七郎,"杀人以尸",真是从古未见。 # 《劳山道士》则说的是一心术不正的 王生 想跟劳山道士学穿房过墙一无阻拦的法术。法师教他念好咒语后,猛然向墙撞去就行了。王生学会后,道士又说:"归宜洁持,否则不验。" 王生下山回家后,向妻子夸耀他学到过墙的本领了,妻子让他试一下,他念好咒语,一头向墙撞去,结果咚的一下,倒在地上,头上撞了个大包,妻儿笑他,他气得大骂法师没有良心。 # 《陆判》说的是一位士子交上一个鬼判,这鬼判为他妻子换了个美人头,为他换了个聪明心。 # 《叶生》,写书生 叶生 "文章词赋,冠绝当时",可是 "时数限人,文章憎命",每次都考不中。幸而还有个做官的好友推荐,但仍是考不中。而这位好友,又要到别处为官,想带他去,一边教自己的孩子,一边让叶生再考,但叶生此时却生病了,难以随行。眼看良机靠山皆要消失,就焦虑而死,可是魂灵却和这位好友一齐走了,好友也不知是魂灵。又是几年,好友儿子在良师 "叶生" 指导下,考中了,当了大官,就帮助自己老师(鬼魂)也考中了,又劝他衣锦还乡。"叶生" 至家,惊呆了妻儿,又看到自己的棺材灵牌,才知道自己已死,随即扑地而灭。这个 "魂从知己" 不觉已死,生不能中,死才能中,而中了后,却又 "灭" 了。这些情节比《范进中举》还要丰富。 # 《红玉》先写 红玉与冯生 燕好,似乎可以结束了,但为冯父发觉,极力反对,冯生只好遵父命决裂。而红玉却又另觅替身卫氏,并极力促成冯卫结婚,生子福儿,琴瑟和谐,似又可结束,却又想不到一士豪要来夺妻,逼得冯生父死妻亡,只能抱儿外逃。家破人亡之际不想来一侠客,杀了仇家,官府抓了冯生,指为杀人犯,后又得侠客救助,才被释放。到家时,大仇虽报,而只剩孤身,何等凄凉,想不到,红玉又带着丢失的儿子来了,又是破镜重圆。真是一会儿花好月圆,一会儿花残月落;一会乐上天堂,一会悲入地狱。大起大落,难有其匹。 # 《翩翩》中讲了一个 浪子 ,离家出走,喝吃嫖赌招摇,弄得一身浓疮,行乞回乡里,为人不齿,不敢回家。就凭这一点 "知耻之心",得到仙女翩翩的救护,帮他治好了病,给他穿上了 "仙衣",并和他结了婚,生了孩子,生活安定。回到故乡的家后,再找翩翩,找不到了。 # 五、《聊斋志异》七大情事 # 《婴宁》 书生 王子服 在元宵灯会偶遇佳人,他捡起姑娘丢落的梅花,相思成疾。表兄吴生诳他说女子是他的表妹,在西南三十里的山里。王子服一人入山寻找,见到佳人,不想竟是自己的姨妹,叫婴宁。婴宁本为狐产女子且随鬼母长大,全然不知道人间的礼数,憨纯无比。当子服向她求寝时,她竟然以 "不惯与生人睡" 相答,并将此事告诉鬼母。 后来,婴宁和子服一起归家。王母和吴生都疑心是鬼,但见她成日爱花爱笑,不避太阳,就让她和子服结为夫妻。婚后还惩治了邻家的浪荡子。一天夜里,婴宁告诉子服她的生事,并求他迁其鬼母的坟与自己的生母和葬。 又过了一年,婴宁生下一子。在娘怀里就不怕生人,和婴宁一样。 # 《聂小倩》 书生 宁采臣 为人豪爽,洁身自爱。 一次他坐在金华一座庙里,同坐的还有一个叫燕赤霞的书生,有奇异的收妖的本领。一女鬼夜里前来勾引宁采臣,被他严词拒绝。第二天,有两个兰溪的过路人在隔壁离奇死了。当晚,女鬼又来,告诉他自己叫聂小倩,被恶鬼胁迫,求他帮助自己脱离苦海。宁采臣按小倩说的把她的尸骨迁到了里自家不远处。小倩随他回到家中。宁采臣妻死后,宁采臣娶小倩为妻。 一天,小倩告诉宁采臣说金华的妖怪就要来寻仇了。于是,宁采臣拿出燕赤霞给他的辟邪的牛皮袋挂在床前。这时小倩已经有了人气,不再害怕辟邪的东西了。第二天晚上,妖怪果然来到,被收服在牛皮袋里化作了数斗清水。 后聂小倩为宁采臣生得二子,皆有功名。 # 《辛十四娘》 明朝正德年间,一姓冯的书生清晨遇一娇艳动人的美人,傍晚时分见美人从一座破庙里出来又回去。于是冯生进去一探究竟,对一老头说明自己爱慕女子之心,并硬闯闺房被赶出。在回家的路上,又误入自己祖母的弟弟的鬼宅。鬼宅的老太太答应为外甥提亲。 果然, 冯生 和 十四娘 结成秦晋之好。 后冯生几番得罪楚银台的公子被害下狱,在辛十四娘的努力下才得以脱险。但经此事后,十四娘对冯生很失望,看透尘缘。第二天容光大变,日渐衰老,半年后像一个八十岁的老太婆了。尽管冯生照顾的很好,还是一病不起,溘然逝去。留下丫头做了冯生的妻子。 后来,老仆人在太华山见到辛十四娘骑着一头青骡子,对老仆人说 "冯郎还好吗?回去告诉他,我已名列仙藉了。" # 《香玉》 一个姓 黄的书生 坐在崂山下清宫里读书。院里有几棵耐冬和几株牡丹。一天,黄生看见一穿白衣的女子在花丛中忽隐忽现,后来又看见一个穿红衣的。他对白衣姑娘顿生爱慕之心,写诗想念,不想,竟感化女郎成其好事。女郎告诉他自己叫香玉,红衣的叫绛雪。直到园里的一株牡丹被买走,才知香玉是花精。 黄生 得知牡丹枯萎死去,就作了 50 首情诗悼念香玉。 终于感动花神,让香玉重生。在香玉柔弱生长的时候,绛雪就陪黄生读书。后来,香玉完全恢复,和黄生过上了夫妻一样的生活。 10 年后,黄生死去。他死前说 "我死了会变成牡丹花下的一株红色花芽,长五瓣叶子。" 果然如他所说。 3 年后,道士的徒弟把黄生化身的牡丹砍掉,随后,园里的耐冬和牡丹相继徇情而死。 # 《公孙九娘》 顺治年间,莱阳的书生到济南去祭拜自己的亲友,遇见死去的同县的朱生央求他给自己做媒,把同样是鬼的莱阳生的侄女嫁给他。 莱阳生 同意后,在侄女家,他邂逅了天仙一般的公孙九娘。由朱生牵红线,人鬼结合。 一天,九娘哭着要求莱阳生把自己的尸骨重新迁到母亲的坟旁,并告诉他,人鬼殊途,不宜久留,别了送给他一双罗袜。 但终因她死后埋在乱葬岗中而使莱阳生无法寻找,终于导致二人爱情失败。 过了半年,莱阳生又去济南,天色暗下,只见一地鬼火,旧地重游,无限惆怅。隐约中看见公孙九娘在坟岗之间,莱阳生连连呼唤:"九娘,九娘……" 却始终不见公孙九娘回答。 # 《白秋练》 书生 慕蟾宫 和父亲到湖北一带跑船做买卖。无事便在船上读诗。不久,被一个叫白秋练的女子仰慕,使其害病。天黑后,女子的母亲和一婢女领白秋练到船上,慕生念情诗将其病治好,见她美貌,便和她共床枕一晚。 后来随父亲回家后,思念成疾,其父只好带他又来到湖北慕生和白秋练相遇的地方。当晚,白秋练来到船上,这次换了是她给慕生念情诗,将其救活。两人由此结合,过了三年生了一个小孩。 一天,白秋练告诉他自己是一条鲤鱼精,现在龙王要招她为妃,并恳求慕生救自己的母亲和让她免于被龙王占有。在白秋练的指点下,慕生遇一道士,得以救回白秋练。 后来慕生的父亲死后,一家人搬到湖北,再也没有回故乡。 # 《娇娜》 一个叫 孔雪笠 的书生,性情文雅仁厚,善作诗。一次路过一家大门,被请进去做客,还做了这家公子的老师。过了半年,正当夏天,孔雪笠的胸口上长了一个碗大的脓疮。公子让表妹娇娜前来医治。娇娜美貌的面容让孔雪笠惊为天人,一时竟忘了疼痛。经过娇娜的医治,孔雪笠的病也日渐好转,而孔雪笠也对娇娜暗生情素。孔雪笠对娇娜思念之情渐渐难以抑制。 公子不知道孔生中意娇娜,却将另一个表妹阿松嫁给了孔生。而不久,娇娜也嫁与吴郎。两人本以萌发的爱情升华为友情。 一天,公子告知孔生他和娇娜,阿松都是狐狸,恳求孔生帮他们避开雷击。结果,孔生冒着被雷击的危险救下娇娜,而娇娜为救孔生两人肌肤相亲,接吻送丸,让孔生起死回生。也是这一天,娇娜的丈夫吴郎一家没有避过劫难。 娇娜只好和表哥一起前去孔生家。 孔生有空就去陪他们兄妹下棋,饮酒。两人再没有谈及儿女私情,终究有缘无份。 # 六、读后感 对于聊斋志异里的故事,我觉得说作者写他的目的是例如什么反封建一类的,是对他的一种亵渎,这里面的故事,实际上就是作者听到的传说或是自己编的故事,只是在一个大的时代背景下,作者通过一些离奇的故事,写出自己的看法、期望与现象。有一定时代的烙印,在客观上折射社会现实,但不等同于主这些这部作品的目的是批判现实的黑暗。故事中有相当的一部分是用来描述人与鬼之间纯洁、真挚、相互扶携的情感。这说明,作者对于当时的时代,是有幻想的。 聊斋倒是说了一个事,那就是到多数的妖精本性也都是善良的。而对于现在的社会,人们时常抱怨世风日下,人们没有了过去的那种淳朴,变得自我、骄横、自私、势力,然而,不变的却仍是,在世上,好人永远比坏人多。我们可以用一个放大镜去观察我们的生活,但观察身边令我们感动的事,还是专门关心社会中不和谐的声音,取决于拿着放大镜的我们。我并不是说睁一只眼闭一只眼,对社会上不公正的事视而不见、置若罔闻,而是用一个理性、客观的角度分析,以求解决矛盾。一个义愤填膺的人,体现的是谁会的正义感,但一群义愤填膺的认为在一起,只顾 "正义" 地指责,将会带来非常不好的谁会影响,使一件本身并不是多么严重的问题,带上各种高帽子,随便是谁,都凑上来发表几句无关痛痒的评论和指责,接着就又有 "世道变了,人心不古" 的感叹,然而这样真的可以解决问题么?与其这样,我们不如利用正义的事,来感化不和谐的声音,这么说或许有一些太过于理想化,但是,至少可以有一个积极的社会氛围,而不是怨声载道。 聊斋告诉我们,妖精也可以与人类和谐相处,那我们又为什么要带上有色眼镜看这样一群人?生活中会有一些人给人的印象就是 "不是好人",但永远不要在不了解一个人之前,给他戴上任何帽子。有的人看上去和颜悦色,但实际上笑里藏刀;有的人看上去总黑着脸,但总会给你最给力的支持。聊斋这些故事,也告诉我要学会了解一个人的本质,不要以貌取人。 下载文档(docx) 下载文档(docx) 文章转载于夸克文档,侵删。

2022/8/18
articleCard.readMore

《水浒传》每章概括

一键下载所有图片(7Z) 一键下载所有图片(7Z) 图片转载于夸克文档 ---《水浒传每回内容梗概_完整版》(点我前往)(打不开点我),侵删。

2022/8/14
articleCard.readMore

Git 常用命令

# Git 常用命令 # 初始化仓库 git init # 添加所有文件 git add . # 添加提交注释 git commit -m "xxx" # 本地代码推送到远程仓库 git push origin master # 拉取远程分支代码到本地 git pull origin master # 创建本地分支 A git branch A # 切换到分支 A git checkout A # 创建并切换到本地分支 A git checkout -b A # 将分支 A 代码合并到当前分支 git merge A # 将当前分支的 HEAD 指向 A 分支 git rebase A # 删除本地分支 git branch -d xxx # 删除远程分支 git push origin -d xxx # 查看所有分支 git branch -a # 重命名当前分支名称 git branch -m new_branch # 重命名指定分支名称 git branch -m old_branch new_branch # 修改最近一次 commit 信息 git commit --amend # 清空 commit 信息 git checkout --orphan new_branch # 删除本地项目的远程仓库连接 git remote rm origin # 查看当前远程仓库 git remote -v # 新项目第一次与远程仓库建立连接 git remote add origin git@github.com:leexiang59/l-helpers.git git push -u origin master

2022/8/2
articleCard.readMore

联想小新为硬件保留2G内存的解决方法

# 联想小新为硬件保留 2G 内存的解决方法 如下图,我们可以看到,系统为硬件保留了 2.1G 内存,实际可用内存减小 在任务管理器中查看 GPU 的占用可以看到,保留内存是被核心显卡共享走了,你电脑的集显需要显存,而他自带的集显是没有显存的,所以会使用你的内存来当显存。这就是为什么会出现为硬件保留 2G 多的原因。 # 方法一: 我们可以将电脑重启,狂按 F2 进入 BOIS (其他品牌的自行百度) 默认是英文,如果看不懂可以先调成中文再继续 找到系统设置 -> 共享显存 然后可以根据自己的需求更改共享显存大小 # 方法二: 如果你的电脑有独显的话,可以将显卡切换为独显,独显自身有专用内存,一般不会占用电脑的内存,如果可以的话,可以自行百度,将显卡切换为独显,集显就别管它了。 # 方法三 (部分设备不行): win+r 打开 msconfig 高级选项 最大内存勾上 点确定应用后重启 开机再到这个位置,勾选然后出现数字后再取消勾选(这时里面有灰色数字里面的数字不用更改),点确定应用。

2022/7/29
articleCard.readMore

博客扩展功能

想看原文请点我!

2022/7/21
articleCard.readMore

VS2022 VC++程序如何生成安装程序

3537d6572f3f0fd5c50ac184a2626861a3cba29c48961332d79e0a844d6ae77dab5195ae09dbf1f6f99213f682ef162fb2ed79c27f8957824e60b871e5072f7ef5df518a665e82ecf207c72a11b92b6fc18370063491488e762a5309ece0cd60fbe2eed2c1dbcc97899419a130f8fb4a3305381147aa806dffc3953b5d73610d00cc2aaa611217e7449448e047c0a3e178a766be4f7426b7b807a2840bcabb260a865274845280b4878ae43a59801578ef2eb45f42f684bdd53cb968305ea36355af14fa668291d56b192f70718bdb6c685a7b0a8f2fa53922f45d82025e4556cda95ec7647c002e6cea33dd53c2aaa3ec82843e409ab886eea3f4559391f1fd4fa086fa660ac28ca9df3c7777840eef398044f8dd01c1d39c3c1f980eb9a6b93b67e11a88f7d9b88d58c530bd7ab417e5ffe20af96fd76408934a7abf7df8c6e555fe2e793a80c980211a22779a32bf5fe2b9fb3cb1d8bedf264b6c7b29adbdc1214043a84f3c3439199b541d1b67f896cf5ff92090fee543d8dc3291f8c1767f4a54eb2a73cfbe37b5aac08e4f744912e66ffb37539d35d43ad4554829a47cf1238840718676fcb3699ff8d8926d58f353399f4af59728e9397972ad4e85b998cbabf4118d6ce3de3bdd73272e235fe83227e5a14d8bdb97ec9af180c7db24de0e9f152dece449458acafb34e4cf3c55c5fa6f9e0638b4c397ab22a52da9283da71144efafd7015ba6ea70e641c225c25ac8851dfd561a70cae95877c42593ca8cab615a65bff9adfbae36f8da17463005dec0865dae51d35ea6bfad79da02fc144bf187578c02a211833fddc14f595fd926afbc923ad42c1938c3903380212a5f11702afb1bcad814fe946cb9df232a5ae9b2e56fa2573e033390ebd4b6f0b7d3770834db57f6986528c18ca5c95b9e9dfecc328860f94cd47d2c21a048193aecceafe93a1053b846342f429fb5b89e0f9ceedd686f72e80d150fd6e3f336129c75f6076878f71444db8f33f04b851e691a7472fec94fa05ec1a17f9c8c5d92c823dabb84ed9ccd07a66f5e19cf059a32eb52490bf4152da27ff6ff0ee7b8036dc68ce159315cdbf8949790626ff05f973c1d400882ff734095b435e85cdc8fa1c18439fd314fcad54bc1fcfba0ed8d5bf7dd2e5eb47d4b467e6316037bc5141629cd16530530f1aebf05e9f0ccbb0728c3b74ada3a32fd9989a9a2419955ddd03e0147428f3b7a963229bead7f6175f9545304063c1668dd91ce8886d0ba3011a6b20392ac5d7b746afdc00e5b72b4f37b13916537f1865e7651af63f5fc7630aafa785617494b86d4c317c0d51da27785c4bff29904bd806ce46cb44747e37c1acb4d5bb9fe49c278d223b57d1101c199c9ee52319ea19156f1ee9e179a0a1485c839009ed186efa30b685acbf5fb8c08a84fe1e2a7cb25b299252885655d4d79f430decdd3a6b91f515d8fcf7f4becf9a1ff629f4a0bae4209e3ceb2d6d50fc23b16ceda12b5c51f725bc6da9fae2d693fcd8721b89612e21d5b5bb391c2bf630b8ee7a20744e3c7fc6d4a7c5c0f7b9b41c7aa42a49a6e3dd90633f0e59448940f888b1f209c641e506f7591c0935bc1486ad8d60a6f91904430f76611a0b4759bc249f340e8511cda223c046a251890b83874f7770defbdfdca5377a076d77d799ae970c39d3e504c044ce43d14620aee30ab498c0a9499d010a3921ecf981b6901f245410ababad84ff119d6eca3da394dd2fedeecfff6434dbfcf3ab349a4589bf7724bde97ae230daa8aba9ba5d2426913bc4a858881c3d3b321df937fa32611433b798782d229cff02e71320093c39a3618ba8fae22a4d791ba093891baffedab6013550619dde61f5c34fa5e7c9ceb003ec5790a2f415918008af77adcc83eecb0097a43fd42398a32b5acac5335c476c5e0747c025700131166414b6af6bd1eba92a0c3390146d11fc4373d619e6a3149515490afa170748a9b52022bd85a8b4b332a35d75185d656c83360340b769121221e093691a6f96fc64ef3724906d5a668d1627b8d840f9ec24140b54d6ccf5c6d0ffa4021b24320a86cf8f714e873cfbed04ebd13cf5e56904d8de2a9f6ec1dceb3ba878cd4c8e1410214f5c4311b78f281a6ac17116ab6e77be484194d7b62cdd9a56893119f11ac7201c5cd60e4167d11f5252e94ae18cd7b91134be659620f3c04b62b0e674d77ed69479342f7f664fb36a91a97a5ebe306968dd459b6b3bba9b0f530dd16ccb8b13893974ec9f5a1a6d725e28d4cc6d161a4387e2c5fbcc96b9291c0f1593268217c4feb13641eff40c390dce1d3a22ebc0cddd8ada1c1470fc9ff686768921edfe0c32f19d5aa0959cfc8ea32710bf6cbddb0151489f2b580bdc62a1bf8b8125be10a6614483be4bbad543fbaca69cc21bb86079df2b60608df5badcf95cb6fb093ff89d11f34d93475dd87a1c2c7540e3a603698e3b547dd2255fb5ec4fb84733c0a15fd3b5f350acc97aea88d963b648e54720cb73fc898b2171fd864d9e925081f7dff5dd96c77390edda003fba06b16fdc843f7ddc520f448b6369b3e8cd1619cc556f2a176aa78b2c7cdbbc1aa7f1718f2cc25ff8f026f7a424665ea6cc60e7a45839a2c3eb20d30813c0125ee06a744c9e87b44214c3c7ef71634bb5e7a70f3a6913b659eb71b390a24b15655ab314f909aa90f8f413f4bb7ef70d9ac3767459bb3205009691fe17abd809b91cb211ad6dbc217dd11d34093726e0345fe53def625d035ad86a58c13efa852da7cbc552dbe0de2e76f4a6fed3e9b0dffdabea90e467fd1fc8e4dc76cddc10106093375ed48db79f5d4420a518823c6b419c78be4fe7ecb75b0a92b8cc289549db7a921c3c217ac1a8eeb707455ca3d95abe2c47b01772735b51108ed466cc0fb1b49a50375d73bc0c82991363b81bf577942203cf4686dbd53e6075444ec1a640fe3d84b25a435cf641cdfdadd75b0887466d344034712e5a301ec767495f45f5223bc13a78b9f58bff5b8f950167a987b31910a9c69ef0168075074cb1667fab7d34a1543bcaff448883a45c37aea25dece520b95d00e68e5f0bf4ce6e3c365ecea2d7a5a876ddfdded12c67b955baa3fa5d261afa70654bdbc54852a54975aa2ac347b2edeb4550ca82576bb8747288d8ebafe5394ffa8002cd9594ad85eb676ef1eb8e663ab120ebbf190885c581c6286cb108827ec1e5de8a463656b03d4929931ec6e8572f15dca0cfffcf35a173c678473dce34735e7b2b68376c3dbc2a0eb476164792b8dfe7eafb14c545462b835f33f335c4c48b0710e99437cd1da0fc522d63689597b62725d8c2ac589a576028a0a680cff276ad3f6a85d2b693970882f7f53dd9ff15cfc8d97293ef226982c8c34079c94a0ba6addf17a24b17d96308abd5191798c33acdec7b9ef21c3a511defa9c3805594f0d305034c4b157560880b9ffb679590c992771e4fb0cb91089e17160b8089e836a0bb074fc38bff37e0397eb12d4e3bdae6505b863fa2e727f1bc645f59edb65edec72d2fff7a855f0f8be611b16477943fdcbac89d14204841f8f7b95a900490d93f7ab1507363830100a842f2c8e938ec679356541c5408b925f080a5b9a1e9032b17f58bd18fc59653e1a92d24a81f62f2a60b927d29271db00c7a0c604f45cc23200e78f86f090c98ecf436ee26c89cd98746e624d6c982bb6a0bbf760d72ff37256a5bebe61f4ab08371771001aa701c8c5084e50fa127c5886bb7a49b0394f131b64e5b4784a974f8109276f2aa13a0269185eff02c74b9bbc5e75f8f79ae6e5f0e163c7b9191c69b3c2fc64f3e395299b71d7bc0f54ef125735ba4b9109563cc4405e49f9051b97a349d6569bc8879f314b4df9a8383c5475b57498e37636267b3d393d1a85a479b0249ffcd36b33f3e86f8db34fe0c3ac7833b1fcd807b84e2efa28905892e838f693b861ba5054782c3673d22c4f71f594ab633a14bfe54f75dab333c747523bbaf66df0a791e438c538914e443e9bb9bcc61518ebfa25a83ba93a6ab88fb8480b6c94e7323b6847be5acd672255e32c5d01f3daf7526a3f803d8c9a4c223ee441c62daf05562a277bb086e7193f12d4b75ec947734cb9f5b34d178f17be154bf3d032080767e1dff337db1745c22bc6cd0a01f136b613e5583771df5b97c7e92aa23c05122126671e36c3407f1d9c07396926a9ab9c4edfb649041aefdda780d0c7bd0ea57b9341102bac3fe7a4c7f18f03155108d2d6f536b789b8ae714453f1ece2e2bf40a4c7f0eaf4200c115084675de3344f9cfc6b2b9e8958e93fc03a4a7a65ed23616e8a158e5af45ac08a49cd5e721724ba0a6764df240392ab00ab276d38a18efdcc6c0fea781352334b854bbf4412c9184ea9eb2d120001d53d6a8d15f60852c5db5cc36fc2baf37275e26d1fa9639c9adb93461de07931cda741275caacf224f5a2a4c49364526a601fd8ee3326b2c91cff96f053d76e238120458a59bdd9869d1fec9584bb22c62eebee28a1bae47a92afc35ec2f9f24fb30ea4e1327b3912ea33424b9c827702abd08dcc8a7f861d1d7d47979bab1127bde4791ba9eba1a6dfd7d6219e3e8300d471398dc21590c3e357d674e33f523ddc471a7623273323b96ce8ed8162a2e5468c18e2744d1f21180e1650a202960faefb86df250356051b5e1b6db401bc779ad23bb58037e14e1b57eb556f4503351863532ed06eb6aedbdb8d3c0ea7979c815a2038cda90ff8fc4414d22665c99ede9747dce8821ef0b3355883ffaef89992d84f3b70d9ad53b7d92990aa39b0c75f6e2dc44ff7c82ecb8532ed9aeca5cd0f504a431ea0c406f859f6ff8ed6ec68dc0d754174e1cd3044c3743b0357bae4f41b8e5e6cde7ed6b5ea6f7a5cf6e98c166797bde9f4e536c64e234251ebbe9db1a117791f510b12523fd68c7ac4ab9a9d721090a3759d7eb3bf38ecb7435398b9d68cf53d554f5ae76abf85488d2471c4a601e52ba2c79d5e6c5e2187c26e8f0bda1df0113119afa4c4931ee565a47913a6530c8c0f010e043694ac6656e7ed2297af571cb58692596f49e28c6da647c553bd5d17c3cc857b6b77ef7731ec95e0cfd471cf6f4ccec7ee469f9a31760610c472958fb27a93beda3a78ecc3881429803bacefe9ff40f121c1b92ca061d2eba6c646bcc457fce4790bde0856935579b4d9a9a9809bbc91d6748afff7f142c1708776245db7ee5c57297c8a543dad66c2f79f5cc6412cb3615e78f126c937d632ef4261de6577c50a5b2a40194390b637f17c602580ca9ec027975de296b6b81b212a0813dc6507bba88257645ae523e68cfb741c5b8702cfde9ef2bc9e39eb77223bed92959ca833b2d5c60c480d25b97324d7c1eb6061d2fe95dd96cacb7f9faa21bea6971f5127c0cd6f0e685e22e69b564029d45ab7c60af777277d88862919c70e350e4d0b1591590a95af04b879e77f2855f779f42f137418d67324d938979f4b2f1054e2c135a549ea614992154c08d04e0203951bfa8ae3ff281b5064b8f191a2f6522a773bd2fb4d0545c8b148886b7281b30547c1978516341851d7d182f04179a5f32e05a258cfc553251c9aa2e5c2df14a3eea67f9120fe32cc053d95785c10ca1ffbb5b94e7796e2552bcc21bf8e6ca645ac0095ed37eac89420522b6cf8a7b801c4d366a1f200afbe5e7c11088cc85136596d512fc2492f84bab2238266fac0623ad8b40527f68030b01fd0fdb4c06f28dd1aa2cf0254e2b6a3ac75460b30707207044ddcac69cea129b3a7e211d656b56b248b7bc7922e31c620581761306b0c5829e7def3e994a5dbb9a0ea912a21c9e01b8566e3c9029b959a7c625a0568a9965a02e7c1b2704a4d6e0e633b8fd0400a3104b1ef7c9a4e88e602630d75003c412a7c7430dfe9146da02b1cdd84cf40764b9594062772a4ff6e4a7ee8f2c9306fc57255e4c5449e5bd3f502fb4f18299ee20bc03a9664f8f4d0da8600086d9eebe2f2d97abc810532396f63bb0f8816a2d09f28be2dc9afb575fe30e891ae13b414efa2acb6965299dafaa015186271885ba1ac3a15f8a92a024006bc8cec227e21251f534e23d5e2fee84ecf67fbc0fea1686833765f6064861b122046bf9d34c1c7ca610d3a829822aaa331796d0191c4020b3d3a70bfc69409d9a9678da75384f7a40d50d3628c61fbfbdc7688c0852ef3921d824d1e7e5b37bf241a75fe1a0f5f34ac6f68d010564ea22b2cf5b2cac2aa92ae52320c7d1e97ca69da86dd7ec2505daaf49964aed2b0a25a4977ea0fdc91de51271b52c5583657cf5f188ec62e241100f93d6ba3fd52d280e9d37e1cc5bea24bce7cb5f919fd980728dc8c34c2aa0306c053f91f42d33ab8ed23eb891943b75943fcb7fca7d4cd952fda38a682ccf03a8878c8e6d064c6948743093ccea974d0dbad6c196af05dac0336aed477afe484d03e19a1590785ddeef1057e8d564664d8781da54d8e302f970745d4f5705a00bbfd990c04c46f3201efd6f2b879185cde0ebc753dedf78c93cddf25c4925c7c67c3a21423e0aeaecafd2beb19b1678db30420c4d5f75550dce58ddfb129e473c591a198c5042736be92685f2e83f1649eb2288ba8a9bb7c60db26f366fca1efbaa53ed8b99588983b2b3d07132319f5dbafd7af052e812a4a9a979b32e1b246b974cd002699536bc9474cab8eb5df6dc3d0e11cd77acc5af6fbc40d71dbab7e126b76c99b59c8091fa5b67cf5d77e6992d07f52b41ac47f19d339b4d56f82c039b9a1f36d569cbeeba0859e2e395e65401be15e0ecf29f39f6366801f5d528034ae20db402f902fd5a792e57e98314f7f7f620e61394ddc4391619161ea4078e201fce66b9f66446b002887326cb6f36d22e055f4765a4ffd9dedf13a22a6ea0 您好, 这里需要密码.

2022/7/21
articleCard.readMore

Markdown超全教程

[TOC] # [Markdown+Typora/VSCode 超全教程] 给大一新生安利的文本神器 Sakiyary 2022/7/16 # 😂 简要介绍 Markdown 是一种轻量型标记语言,是一种语法。以 .md 结尾的文本文件就是 Markdown 文件。相较于 Word, 它更加像是 HTML 语言或是 LaTeX\LaTeXLATE​X, 并不是最淳朴的那种 "所见即所得". 它处处透露着一种极简主义。高效简洁清晰的同时,又很简单。看起来舒服,语法简单,尤其在处理纯文本上有很大的优势. 它相较于 Word, 兼容性非常高,可以跨平台使用,不用担心奇奇怪怪的版本兼容问题。同时,有许多网站都支持或正在使用 Markdown 语法。如 Github (等一系列代码托管平台), StackOverflow (等答疑平台), 简书,语雀 (等一系列笔记平台). # 📐 实际应用 所有要写文本的时候都可以用上 Markdown! 它可以让你不再纠结什么字体,什么样式,什么排版。而且逻辑清晰,层次分明. 像我大一的时候就用 Markdown 来写各种笔记,演讲稿,课程论文,实验报告,代码的 README.md ... 包括本教程文档. # 🍴 工具 Markdown 只是一种语法。那么用来写 Markdown 的文本编辑器呢?我推荐的是 Typora 或者 VS Code # Typora Typora 应该是被广泛用于写 Markdown 的文本软件,就和 Markdown 语法一样高效。而且它还有很实用的扩展语法与自定义样式的功能。其能将 .md 导出成多种文件,如 .pdf , .html , .docx (没想到吧,能导出到 Word) 但是现在 Typora 已经发布正式版并且变为收费软件。中文官网在此 Typora 官方中文站 . 我当然是推荐大家都用正版啦。不过价格是永久版¥89, 好在可以用在 3 台设备上。如果和你的两位同学 / 舍友均摊一下,每人就只要¥30, 和一张游戏月卡差不多. 至于盗版以及破解方法在此随便找一种改注册表时间方法的不介绍 (还挺多的其实). 还有一种免费白嫖的方法就是安装测试版 / Beta 版。官网有历史版本的下载链接 Typora 历史版本下载页 白嫖 Beta 版已经寄了,要么支持正版要么去学习一下破解方法吧 (还是忍不住啦,看上面的链接👆) # VS Code 这是微软家的开源文本编辑器,理论上来说所有代码,语言,都可以用 VS Code 来写,同样是非常的简洁好用。在下载插件 Markdown All in One 后对 Markdown 的基础支持也是非常的好。若在 VS Code 下载 Markdown 各种附加扩展,就能获得比 Typora 更加丰富的扩展语法与操作. # 其他 大部分 IDE, 像 Jetbrain 的全家桶里应该每一款,都支持 Markdown 语法,在此不多赘述. 本文档主要使用 Typora 进行演示,同时会介绍许多 Typora 所包含的扩展语法. # 🍭 基础教程 当有多种标记方法时我会倾向其中一种. 标题有 * 表示该为扩展语法,仅在 Typora 或 添加了扩展的 VS Code 本地生效,在大多数平台上并不认可. # 0. 写 Markdown 的第零步 我们写文本的时候大多写的是中文,可是输入法在输中文时使用的标点为全角标点,如 ,。?!()【】:;“” . 这些标点是不被 Markdown 所认可的,也是无法转义的. 我建议大家写 Markdown 的时候都用半角标点,即英文标点,如 ,.?!()[]:;"" . 且每个半角标点在文本使用时加上后置空格,符合英文标点的书写规范,也更加美观. 以微软自带输入法举例,在使用中文输入法时按下 Ctrl + .(这是个句号) , 切换标点的全角与半角。这样即可中文输入 + 半角标点. # 1. 标题 [数个 "#" + 空格 前置] 1 2 3 4 5 6 # 一级标题 ## 二级标题 ### 三级标题 #### 四级标题 ##### 五级标题 ###### 六级标题 标题会在目录与大纲分级显示,可以跳转. 在 Typora 中建议开启 严格模式 ,即不应为 #标题 ,应为 # 标题 . 应该要手动补上空格,使得 Markdown 语法在其他文本编辑器上兼容. # 2. 强调 [用 "**" 或 "__" 包围] 1 2 **欢迎报考南京大学!** (我喜欢用这种) __欢迎报考南京大学!__ 或者选中想要强调的文字按下 Ctrl + B . E.G. 欢迎报考南京大学! # 3. 斜体 [用 "*" 或 "_" 包围] 1 2 *欢迎大佬来浇浇我各种知识* (我喜欢用这种) _欢迎大佬来浇浇我各种知识_ 或者选中想要强调的文字按下 Ctrl + I . E.G. 欢迎大佬来浇浇我各种知识 (P.S. 斜体并强调 [用 "***" 或 "___" 包围]) # 4. 删除线 [用 "~~" 包围] 1 ~~我宣布个事儿, 我是Sabiyary!~~ 我宣布个事儿,我是 Sabiyary! # 5. * 高亮 [用 "==" 包围] (注意:此为扩展语法) 1 ==我喜欢黄色, 也喜欢绿色== 我喜欢黄色,也喜欢绿色 # 6. 代码 [用 "`" 包围] 1 `sudo rm -rf /*` sudo rm -rf /* (没事别乱敲这个!) "请输入管理员密码: (闪烁的光标)" # 7. 代码块 [按三个 "`" 并敲回车] 1 2 3 4 5 6 7 8 ``` // 这里就可以开始输入你要的代码了 #include <stdio.h> int mian() { print(“Hello, world!\n"); retrun O; } ``` // (这三个"`"文本编辑器会帮你自动补全 一般不用手动输) ``` 会变为 ```` + 对应语言 . # 8. 引用 [">" + 空格 前置] 1 2 > 24岁, 是学生. > > 学生特有的无处不在(恼) 24 岁,是学生. 学生特有的无处不在 (恼) # 9. 无序列表 ["-" 或 "+" + 空格 前置] 1 2 3 - 一颗是枣树 (我喜欢用这种) + 另一颗还是枣树 * (其实这种也可以, 不过由于在 Typora 中很难单个输入, 故不常用) Tab 会缩进一级. 一颗是枣树 另一颗还是枣树 # 10. 有序列表 [数字 + "." + 空格 前置] 1 2 3 4 我来这里就为了三件事: 1. 公平 2. 公平 3. 还是tm的公平! Tab 会缩进一级. 公平 公平 还是 tm 的公平! # 11. * 上标 [用 "^" 包围] (注意:此为扩展语法) 1 C语言中int的上限是 2^31^ - 1 = 2147483647 int 的上限是 231 - 1 = 2147483647 # 12. * 下标 [用 "~" 包围] (注意:此为扩展语法) 1 H~2~O 是剧毒的! 2O 是剧毒的! # 13. * 注释 ["[^]" 后置] (注意:此为扩展语法) 1 2 > 今日我们相聚于此, 是为了学习 Markdown 的使用, 它的教程对于全体「观众」而言, 值得足足两个硬币的支持鼓励![^1] [^1]: 沃兹·基·硕德 改编自「公鸡」普契涅拉. 今日我们相聚于此,是为了学习 Markdown 的使用,它的教程对于全体「观众」而言,值得足足两个硬币的支持鼓励![^1] # 14. 链接 [常用 "[]" + "( )" 分别包围文本与链接] (注意:文内跳转为扩展用法) 1 2 [来看看我贫瘠的仓库罢](https://github.com/jdjwzxAPI) [基础教程: 12. 下标](#12. 下标 [用 "~" 包围]) Ctrl 并 单击鼠标左键 即可跳转. 来看看我贫瘠的仓库罢 # 15. 任务列表 ["- []" + 空格 前置] 1 2 3 4 TodoList: - [ ] 刷B站 - [ ] 写代码 - [ ] 起床 x 代替 [ ] 中的空格来勾选任务列表。在 Typora 中可以直接用鼠标左键单击勾选框. 刷 B 站 写代码 起床 # 16. 表格 [用 "|" 绘制表格边框] 1 2 3 4 | 学号 | 姓名 | 年龄 | | :--- | :---: | ---: | (引号的位置代表着 左对齐, 居中, 右对齐) |114514|田所|24| |1919810|浩三|25| 学号 姓名 年龄 114514 田所 24 1919810 浩三 25 # 17. 图片 [直接拖进来或者复制粘贴] 1 ![图片](图片的位置) 我还是会选择拖进来或者复制粘贴啦~在 Typora 的设置里也可以改图片的储存方式. # 18. 分割线 [按三个 "*" 或 "-" 或 "_" 并敲回车] 1 2 3 4 *** --- (我喜欢用这种) ___ // (其实按三个及以上都可以) * 与 _ 均会自动补全,所以我觉得 - 最为方便. # 19. Emoji 表情 [":" 前置] (注意:英文输入为扩展语法) 1 2 3 4 :sweat_smile: :drooling_face: :clown_face: // (敲回车或者鼠标点击, 后置的":"一般不需要手动输) 硬编码的 (刻进 DNA 里) 太抽象了 全 Emoji 的网站,非常好用!我之前的 C 语言大作业也是从这里下载的资源! # 🔥 进阶教程 # 1. 目录 [自动生成] 1 [TOC] (此为 Typora 特有的, 如本文档开头) 命令面板 (即 VS Code Command Palette) 输入 Create Table of Contents 自动生成目录,且可在扩展设置中细调目录参数. # 2. 内联 HTML 代码 [用 "<> </>" 包围] 1 2 3 4 5 <div style="text-align:center"> <font style="color:red">我不会 HTML 呜呜呜... 浇浇我</font> </div> <center>简单的文字居中也可以这样</center> <u>我差点忘了还有下划线这东西...</u> HTML 来写. .md 文件可以直接导出成一个网页. Ctrl + U . # 3. 内联 LaTeX\LaTeXLATE​X 公式 [用 "$" 包围] (注意:部分编译器会不识别部分符号) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 $\LaTeX$ 是最好用的论文排版语言! 不信你看! $a^n+b^n=c^n$ $$ %\usepackage{unicode-math} \displaystyle \ointctrclockwise\mathcal{D}[x(t)] \sqrt{\frac{\displaystyle3\uppi^2-\sum_{q=0}^{\infty}(z+\hat L)^{q} \exp(\symrm{i}q^2 \hbar x)}{\displaystyle (\symsfup{Tr}\symbfcal{A}) \left(\symbf\Lambda_{j_1j_2}^{i_1i_2}\Gamma_{i_1i_2}^{j_1j_2} \hookrightarrow\vec D\cdot \symbf P \right)}} =\underbrace{\widetilde{\left\langle \frac{\notin \emptyset} {\varpi\alpha_{k\uparrow}}\middle\vert \frac{\partial_\mu T_{\mu\nu}}{2}\right\rangle}}_{\mathrm{K}_3 \mathrm{Fe}(\mathrm{CN})_6} ,\forall z \in \mathbb{R} $$ $ 包围为单条公式,按下两个 $ 并敲回车即生成公式块. LaTeX\LaTeXLATE​X 是最好用的论文排版语言!不信你看! an+bn=cna^n+b^n=c^nan+bn=cn # 4. * 网络图床 (这是学长给我的网络图床教程,我并未实践过...) 例子。新用户免费试用 6 个月,另外还可选择七牛云或者路过图床. # 5. *Typora 的常用快捷键 按键 效果 按键 效果 Ctrl + D 选中当前词 Ctrl + L 选中当前句 / 行 Ctrl + E 选中当前区块 Ctrl + F 搜索当前选中 Ctrl + B 加粗当前选中 Ctrl + H 替换当前选中 Ctrl + I 倾斜当前选中 Ctrl + U 下划当前选中 Ctrl + K 将当前选中生成链接 Ctrl + J 滚动屏幕将选中滚至顶部 Ctrl + W 关闭当前窗口 Ctrl + N 打开新窗口 Ctrl + O 打开文件 Ctrl + P 搜索文件并打开 Ctrl + 回车 表格下方插入行 Ctrl + , 打开偏好设置 Ctrl + . 切换全角 / 半角标点 Ctrl + / 切换正常 / 源代码视图 Ctrl + Shift + - 缩小视图缩放 Ctrl + Shift + + 放大视图缩放 还有一些不常用的 / 三键的快捷键不在此列出. # 6. *Typora 的主题样式与检查元素 Markdown 在编译后约等于 HTML. 而 Typora 的正常视图就是编译后的 Markdown, 故 Typora 的主题样式本质就是 CSS 文件. 调试模式 后即可在正常视图右击打开 检查元素 ,在其中就可以完全将 Markdown 文件当成 HTML 来编辑. # 💯 总结 至此,Markdown + Typora / VSCode 的手册教程也告一段落. LaTeX\LaTeXLATE​X 来写论文也有帮助。标记语言正是为了摆脱 Word 那种虽然 "所见即所得", 但又过于花哨浮华,很差的兼容性与闭源的编码的缺陷。当你能掌握这样的 "所写即所得" 时,你肯定会感受到用 Markdown 这类语言来处理文本的妙处!

2022/7/20
articleCard.readMore

jdjwzx233的博客

如无特别声明,该博客文章均为 jdjwzx233 原创,转载请遵循署名 - 非商业性使用 4.0 国际(CC BY-NC-SA)协议,即转载请注明文章来源。 如发现用户发布违规内容或评论,管理员将封禁其 IP 地址!(所有 jdjwzx233 的站点将不可访问。如果有误封,请联系 admin@jdjwzx233.cn 进行申诉) 本博客使用 hexo 进行搭建,采用 shoka 主题。 本博客属于非商业性质的博客。 如需联系 jdjwzx233,请点击这里,或通过添加好友的方式联系 jdjwzx233-bot(QQ: 1438148243)。在进入 QQ 后,向 jdjwzx233-bot 发送指令 "!rg",即可获取 jdjwzx233 的联系方式。获取好友验证码请参考第 7 条。 如果博客文章、使用的图片等侵犯了您的版权或给您带来了损失,请联系 admin@jdjwzx233.cn。 jdjwzx233-bot 的好友验证码为:jdjwzx233blogyyds(不定时更改)。 jdjwzx233-bot 将于 2023 年二月份关闭,客服业务已经转移到 jdjwzx233-Blog 上。您现在可以通过博客右下角的咨询按钮联系 jdjwzx233-Blog 的管理员。 如果喜欢 jdjwzx233-Blog,请点击这里订阅,获取 jdjwzx233-Blog 的最新动态。 如果您访问本站,即表示您同意本站的隐私政策、Cookie 政策、服务条款和免责声明。如果您不同意相关政策和条款,请勿访问本站。您可以联系 admin@jdjwzx233.cn 删除您在本站中的一切信息(包括评论、账户、文章等)。 为了尊重和保护访客和用户的隐私权,我们提供了一种方便的方式来关闭网站跟踪器。您可以在网站底部找到相应选项,以便自主选择是否接受网站跟踪。我们鼓励您在使用我们的网站时行使您的选择权,以获得更加个性化和符合您需求的浏览体验。 本站点已启用腾讯云 CDN 加速,加速网址:www.jdjwzx233.cn 您可以使用爱发电赞助本博客的运营和开发。 赞助感谢名单:https://sponsorme.jdjwzx233.com/ 爱发电-jdjwzx233 每月5元,感谢您的赞助 广告: LightNode:拥有高质量香港 CN2 GIA 节点与原生 IP (河内、曼谷、华盛顿、柬埔寨)。充值 10 美元,最多账户获得 30 美元,10 美元可用 5 个月,相当于不要钱。(支持支付宝、银联、paypal 等支付方式)。对于想用 VPS 解锁 **「Netflix、 TikTok」** 或者其他流媒体,以及对 CN2 有需求的都可以看看。官网链接:www.lightnode.com 又拍云:又拍云有非常多的优惠:加入又拍云联盟 (网站需备案,要在网站 / 应用底部添加又拍云 LOGO 并指向官网) 后,可以获得每月 10G 储存空间和 15G 的 CDN 流量 (按年发放,以 67 元的代金卷发放到账户);新用户注册 (点我注册) 还可以直接获得 61 元的代金卷 (有效期一年)。在这些优惠的加成下,你可以零成本建站。 Ciallo~(∠・ω< )⌒★

2022/2/3
articleCard.readMore

Hello World

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub. # Quick Start # Create a new post 1 $ hexo new "My New Post" More info: Writing 也可以手动添加文档 -> 文件名.md 放入:主文件夹 /source/_posts/ 中。 一定要在文档开头添加: 1 2 3 4 5 6 7 8 9 10 11 12 --- title: 文章的标题 date: 2022-01-01 01:01:01 categories: - [博客的分类1] - [博客的分类2] - [博客的分类3] tags: - 标签1 - 标签2 --- 这里开始使用Markdown书写博客正文 否则会出现问题!!! # Run server 1 $ hexo server More info: Server # Generate static files 1 $ hexo generate More info: Generating # Deploy to remote sites 1 $ hexo deploy More info: Deployment

2022/2/2
articleCard.readMore