找到
177
篇与
技术教程
相关的结果
- 第 2 页
-
安卓高版本无 ROOT 抓包教程 【安卓逆向】无 Root!HTTPS 抓包竟能如此简单?小白也能秒懂 图片 📌 开篇痛点 安卓 7.0 版本(包括)之后,系统不再信任根目录之外的证书。 "想抓包分析 APP 数据,但手机没 Root?HTTPS 加密的包一抓就断网? 别慌!今天教你用『小黄鸟+虚拟机』这对神器,0 门槛破解无 Root 抓包难题!" 🌟 为什么这个方法牛? 无需 Root:解 BL 锁、刷机统统不需要! 安卓全版本通吃:安卓 7.0 以上高版本照样抓! 保姆级教程:跟着做 10 分钟搞定,附避坑指南! 🛠️ 工具准备 小黄鸟 HttpCanary(抓包神器) https://wwb.lanzouf.com/iNZSN026e9qd VMOS 安卓虚拟机(模拟带 Root 的系统环境) https://www.vmos.com/ 工具截图图片 🚀 保姆级操作步骤 第一步:真机安装工具 真机下载安装 小黄鸟 HttpCanary 和 VMOS Pro(虚拟机)。 小黄鸟设置:进入设置 →SSL 证书 → 导出为 System Trusted (.0) 格式,证书会保存在手机 /HttpCanary/cert/ 目录下。 证书导出图片 第二步:虚拟机开“外挂” 启动 VMOS → 新建一个 安卓 7.1 精简版系统(自带 Root 权限)。 导入文件:在虚拟机内用“文件中转站”功能,导入 目标 APP 和 小黄鸟生成的.0 证书。 挂载证书: 用 MT 管理器(需虚拟机内 Root 权限)将证书复制到虚拟机的 /system/etc/security/cacerts/ 目录。 如果提示“只读”,记得在 MT 管理器中 挂载读写权限! 虚拟机操作图片 第三步:抓包实战! 真机启动小黄鸟 → 设置目标应用为 VMOS。 虚拟机内打开目标 APP → 真机小黄鸟自动开始抓包! 抓包成功:所有 HTTPS 流量明文展示,随便看、随便改! 抓包结果图片 ⚠️ 避坑指南 证书复制失败 → 检查虚拟机是否开启 Root 权限,或换用 Root Explorer 操作。 抓不到包 → 确认小黄鸟证书类型是 .0 格式,且 VMOS 网络通畅。 虚拟机卡顿 → 关闭真机后台无关应用,或换用低配版虚拟机系统。 📢 文末 "你学会了吗?赶紧试试看! 评论区 留下你的实战结果,或遇到的坑,博主帮你解答! 转发 给身边的技术宅,一起解锁新姿势!"
-
使用 HTML、CSS 和 JavaScript 构建简易屏幕录像机 欢迎各位参与这个简单易行的屏幕录像项目!我们将仅使用传统的 HTML、CSS 和 JavaScript 共同完成。您可能会疑惑:为何需要这样的工具?答案在于屏幕录制对教程制作、演示汇报、缺陷报告等诸多场景至关重要。无论您是为频道创建分步教学视频,还是向潜在客户展示作品集,这类应用都不可或缺。本文将带您打造一款简约却强大的屏幕录像工具,完全基于 HTML、CSS 和 JavaScript 实现。 工具准备 如先前所述,本项目无需任何第三方库。但若您零编码经验,建议先观看此教程学习代码编辑器基础。 项目目标 本工具支持用户直接通过浏览器录制屏幕画面及完整音频。点击录制按钮后,系统将提示选择录制区域(如 Chrome 标签页),支持多窗口选择或全屏录制。右下角的 "同时共享音频" 选项可自由开关。录制前设有倒计时,最终视频以 WebM 格式下载。 代码轻量无依赖,充分利用浏览器原生 API。让我们深入解析: 架构分解 HTML 构建界面:包含视频预览、录制按钮和下载链接 CSS 样式设计:响应式布局与动感倒计时层 JavaScript 核心功能:屏幕捕捉、视频录制与下载逻辑 现在让我们深入代码实现。 HTML 结构 创建 index.html 文件,编写基础界面代码(有经验者可自定义调整): <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" href="style.css" /> <script src="script.js" defer></script> <title>在线屏幕录制</title> </head> <body> <div class="countdown" id="countdown"></div> <div class="screen-recorder"> <h1>开启屏幕录制</h1> <video controls preload="none" id="video"></video> <nav> <button type="button" class="btn" id="btn" aria-label="开始录制">录制</button> <a href="#" class="btn" id="link" aria-label="下载录制视频" download="recording.webm">下载视频</a> </nav> </div> </body> </html>video 元素展示录制内容,button 和 a 分别控制录制与下载。 CSS 样式 创建 style.css 美化界面(CSS 新手可参考 W3School 教程): 关键样式说明: 全局重置:统一边距与盒模型 居中布局:使用网格布局实现垂直水平居中 倒计时层:全屏半透明遮罩与大号数字显示 响应式视频:自适应屏幕尺寸 按钮设计:统一风格与悬停效果 移动适配:媒体查询优化小屏体验 * { padding: 0; margin: 0; box-sizing: border-box; } body { width: 100vw; min-height: 100vh; display: grid; place-items: center; background-color: #f4f4f4; } .countdown { visibility: hidden; color: green; font-size: 10rem; font-weight: 900; background-color: rgba(0, 0, 0, 0.5); /* 半透明黑色背景 */ position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: 10000; display: flex; align-items: center; justify-content: center; } .screen-recorder { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2rem; width: 90%; max-width: 1000px; padding: 2rem; background-color: #fff; color: #202020; border-radius: 10px; box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.2); } .screen-recorder video { width: 100%; max-width: 782px; aspect-ratio: 16 / 9; max-height: 440px; box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.1), -2px -2px 5px rgba(0, 0, 0, 0.1); border-radius: 10px; display: none; } h1 { text-transform: capitalize; font-size: 3rem; font-weight: bold; color: #202020; } .btn { background-color: #428bca; color: #fff; font-weight: 900; padding: 0.75rem 1.5rem; border-radius: 0.5rem; cursor: pointer; text-transform: capitalize; border: 1px solid #428bca; transition: background-color 0.3s ease, color 0.3s ease; } .btn:hover, .btn:focus { background-color: #357ec7; outline: 2px solid #357ec7; outline-offset: 2px; } a { text-decoration: none; margin-inline-start: 20px; display: none; } @media (max-width: 768px) { .screen-recorder video { width: 100%; height: auto; } h1 { font-size: 2.5rem; } .btn { padding: 0.5rem 1rem; font-size: 1rem; } .countdown { font-size: 6rem; } }JavaScript 功能 创建 script.js 实现核心逻辑: 隐藏内容,请前往内页查看详情 功能解析 事件驱动:按钮点击触发录制流程 媒体捕获:使用 getDisplayMedia 获取屏幕流,getUserMedia 获取音频 倒计时机制:Promise 实现 3 秒倒计时 录制控制:MediaRecorder API 处理视频流 下载生成:Blob 对象转换下载链接 常见问题解答 Q: 能否录制系统音频? A: 受浏览器安全策略限制,系统音频录制可能存在限制,建议使用麦克风输入。 Q: 无法录屏的解决办法? A: 确保浏览器支持 getDisplayMedia API,最新版 Chrome/Firefox 均可。 Q: 如何提升音质? A: 代码已启用回声消除与降噪,建议外接优质麦克风。 Q: 支持暂停录制吗? A: 当前版本未实现,可停止后重新开始。 优劣分析 优势局限无依赖轻量级仅支持现代浏览器简单易实现无高级编辑功能音视频同步录制音频设备兼容性问题Webm 格式下载需转换格式兼容播放响应式设计无实时预览功能通过本文,您已掌握构建基础屏幕录像工具的全流程。现在即可动手实践,打造专属的录屏解决方案! 演示站:http://web.bri6.cn/tool/screen-record/ 图片
-
有了 Fiber 之后的 PHP 会发生怎样的变化? PHP 引入 Fiber(纤程)是一个非常重大的特性,它为 PHP 带来了类似协程的并发编程能力,使得 PHP 能够实现 异步非阻塞 编程模式。 Fibers 是基于用户态的轻量级线程,能够有效地管理任务的暂停与恢复,从而使得 PHP 能够处理更加复杂的并发场景。 具体来说,Fiber 让 PHP 在面对 I/O 密集型 或 高并发 的场景时,比传统的同步模式更加高效。 1. Fiber 在 PHP 中的作用 Fiber 允许开发者在 同一线程中 执行多个任务,并可以在任何时候暂停和恢复执行。 这种机制在传统的 PHP 中是不可行的,因为 PHP 是基于 同步 执行的(即每次只能执行一个操作,且操作之间是阻塞的)。使用 Fiber 后,PHP 能够实现类似 协程 或 绿色线程 的行为。 与传统多线程的区别: Fiber 是 用户态协程,不依赖操作系统线程调度,所以它比操作系统级线程更轻量。它通过显式的 yield 和 resume 来控制程序的执行流程。 多线程 是操作系统层面的线程切换,通常需要更多的资源和开销。 2. Fiber 带来的变化 2.1 异步非阻塞编程 在没有 Fiber 之前,PHP 并不擅长处理异步操作,尤其是在处理 I/O 密集型 操作(如数据库查询、文件操作、HTTP 请求等)时,PHP 会在执行这些操作时 阻塞,直到操作完成才会继续执行后续的代码。 通过 Fiber,PHP 可以在一个请求中同时执行多个任务,像 异步编程 模型一样,在执行阻塞操作时挂起当前任务,让出 CPU 资源,从而执行其他任务。 当阻塞操作完成时,Fiber 会恢复原来的任务继续执行。这种模式类似于 Node.js 的 事件循环 和 JavaScript 的 async/await。 2.2 提升并发处理能力 使用 Fiber,PHP 可以在同一进程中实现 多任务并发执行,特别是在处理多个 I/O 操作 时,Fiber 的引入避免了每次等待 I/O 操作完成时的阻塞。这大大提升了高并发场景下的性能。 例如,可以同时发起多个数据库查询、多个 HTTP 请求,所有操作都可以在同一个进程内并行执行,极大地减少了因等待而浪费的时间。 2.3 轻松实现协程 协程 是一种轻量级的线程,它允许函数在执行时暂停并在稍后的某个时间点恢复执行。在 PHP 中,Fiber 让协程变得更加易于实现,减少了依赖外部扩展或框架的复杂性。 2.4 增强的代码可读性和维护性 协程 编程模式通常能显著提高代码的可读性和维护性。通过 yield 和 resume,你可以通过同步的代码逻辑来处理异步任务,避免了回调地狱(callback hell)或复杂的状态机逻辑。 3. 如何使用 Fiber? PHP 8.1 引入了 Fiber 类。通过使用 Fiber,你可以创建协程,暂停和恢复执行。下面是一个简单的示例,展示了如何使用 Fiber 来实现异步任务: <?php $fiber = new Fiber(function (): void { echo "Fiber started\n"; // 模拟异步任务 Fiber::suspend(); // 暂停 Fiber,模拟等待某个异步任务完成 echo "Fiber resumed\n"; }); // 启动 Fiber echo "Main: before fiber\n"; $fiber->start(); // 输出: Fiber started // Fiber 暂停,主线程继续执行 echo "Main: after fiber suspend\n"; // 输出: Main: after fiber suspend // 恢复 Fiber $fiber->resume(); // 输出: Fiber resumed echo "Main: after fiber resumed\n"; // 输出: Main: after fiber resumed在这个例子中: Fiber::suspend():用于暂停当前 Fiber 的执行,返回控制权给调用它的主线程或其他 Fiber。 fiber->resume():恢复 Fiber 的执行,继续执行从 suspend 暂停的地方。 4. Fiber 的应用场景 4.1 异步数据库操作 传统的数据库操作是同步的,当一个查询正在执行时,PHP 会一直等待,直到查询返回结果。 这对于并发高的场景来说,效率低下。使用 Fiber,你可以发起多个数据库查询,并让每个查询在等待过程中挂起,主线程可以继续执行其他任务,直到查询完成。 <?php use Amp\Loop; use Amp\Mysql; Loop::run(function () { $db = yield Mysql\connect('mysql:host=127.0.0.1;dbname=test', 'root', 'password'); // 发起多个查询并等待结果 $result1 = yield $db->query('SELECT * FROM users'); $result2 = yield $db->query('SELECT * FROM orders'); // 处理查询结果 $users = yield $result1->fetchAll(); $orders = yield $result2->fetchAll(); var_dump($users, $orders); });在这个例子中,两个查询通过 Fiber 实现并发执行,而不会阻塞 PHP 程序。 4.2 高并发 HTTP 请求 Fiber 也适用于发起多个 HTTP 请求的并发处理,特别是在进行大规模爬虫或并行数据抓取时,可以大大提升效率。通过 Fiber,多个 HTTP 请求可以同时进行,而不需要等待某一个请求完成后才能开始另一个。 <?php use Amp\Http\Client\HttpClientBuilder; use Amp\Http\Client\Request; use Amp\Loop; Loop::run(function () { $client = HttpClientBuilder::buildDefault(); $request1 = new Request('https://example.com/page1'); $request2 = new Request('https://example.com/page2'); $response1 = yield $client->request($request1); $response2 = yield $client->request($request2); echo yield $response1->getBody(); echo yield $response2->getBody(); });在这个例子中,request 和 response 操作都可以并发执行,提高了 I/O 操作的效率。 4.3 长时间运行的任务 在 CLI 或其他长期运行的 PHP 脚本中,如果有多个任务需要交替执行,Fiber 可以非常方便地切换任务,避免单个任务阻塞整个脚本。例如,可以在处理大批量数据时,利用 Fiber 实现任务的暂停和恢复,避免长时间的阻塞。 5. Fiber 的挑战与限制 尽管 Fiber 为 PHP 带来了异步编程的优势,但它也有一定的局限性和挑战: PHP 传统的同步编程模型不兼容:Fiber 需要开发者适应新的编程模型,可能需要重构现有的同步代码来支持 Fiber。 性能开销:虽然 Fiber 是用户态协程,开销比线程小,但它仍然带来了一定的内存和执行成本,尤其是在需要频繁暂停和恢复任务的场景下。 第三方库支持有限:尽管 Fiber 提供了强大的并发支持,但并不是所有的 PHP 扩展和库都与 Fiber 兼容。例如,某些扩展或库可能依赖于 PHP 的传统同步模型,不支持或难以适配 Fiber。 6. 未来发展 随着 PHP 8.1 引入 Fiber,这一特性将逐步影响整个 PHP 生态系统。 可以预见,在未来,更多的框架、库和工具将开始支持 Fiber,为 PHP 开发者提供更强大的并发编程能力。 此外,结合 Swoole、ReactPHP 等库,Fiber 可能成为构建高性能异步 PHP 应用的核心技术之一。 总结 Fiber 为 PHP 带来了异步编程的能力,特别是在 I/O 密集型任务和高并发场景下,它能够显著提升 PHP 的执行效率。 开发者可以通过 Fiber 实现类似协程的并发任务管理,并通过 yield 和 resume 控制任务的执行流,从而避免传统同步编程模型中的阻塞问题。 然而,Fiber 也需要开发者对新的编程模型进行适应,尤其是在与现有同步代码和第三方库的兼容性上。 随着时间的推移,Fiber 的使用将更加广泛,并且与其他异步框架和工具的集成会进一步提升 PHP 的性能和开发体验。 图片 参考链接: 以上就是本篇分钟的全部内容,希望各位程序员们努力提升个人技术。最后,小编温馨提示:每天阅读 5 分钟,每天学习一点点,每天进步一点点。 图片
-
JavaScript 意外的副作用:修改共享变量 由于闭包可以访问外部函数的变量,如果不小心修改了这些变量,可能会导致意想不到的副作用。 function outer() { let counter = 0; return { increment: function() { counter++; }, getCount: function() { return counter; } }; } const myCounter = outer(); myCounter.increment(); myCounter.increment(); console.log(myCounter.getCount()); // 输出 2在这个例子中, 虽然我们希望 counter 变量是 outer 函数的私有变量, 但是通过闭包, 我们仍然可以在外部修改它. 解决方法: 最小化共享: 尽量减少闭包对外部变量的修改,优先使用局部变量。 使用不可变数据: 如果外部变量是对象或数组,尽量使用不可变数据结构,避免意外修改。 更明确的接口: 如果确实需要修改, 那么就通过定义明确的接口来修改。 图片
-
JavaScript 循环中的闭包陷阱:“意料之外” 的共享 闭包 (Closure) 无疑是 JavaScript 中最强大、最迷人的特性之一。它赋予了函数访问其定义时所在词法环境的能力,即使该函数在其定义的作用域之外执行。凭借闭包,我们可以实现数据封装、模块化、柯里化等高级编程技巧。 然而,硬币的另一面是,闭包也常常被视为 JavaScript 中最容易误解、最容易出错的特性之一。稍有不慎,就会掉入闭包的“陷阱”,导致内存泄漏、意外的变量共享等问题。 图片 在循环中使用闭包时,很容易出现意外的变量共享问题。 图片 在这个例子中,我们期望 setTimeout 的回调函数(闭包)分别输出 0, 1, 2, 3, 4。但实际输出的却是 5 次 5。这是因为 setTimeout 是异步执行的,当回调函数执行时,循环已经结束,i 的值已经变成了 5。而且,由于使用了 var 声明 i,所有的回调函数共享的是同一个 i 变量。 解决方法: 使用 let 声明循环变量:let 具有块级作用域,每次循环都会创建一个新的 i 变量,避免了变量共享。 图片 使用立即执行函数 (IIFE):创建一个立即执行函数,将循环变量 i 作为参数传递进去,形成一个闭包,每次循环都会创建一个新的作用域。 图片 使用bind方法:使用 bind 方法将循环变量 i 绑定到回调函数上。 图片
-
JavaScript 内存泄漏:“永不消逝” 的变量 闭包最常见的陷阱就是内存泄漏。当一个闭包引用了外部函数的变量,而这个闭包又被长期持有(例如,作为事件处理程序或定时器回调),那么外部函数的变量就无法被垃圾回收,导致内存泄漏。 function createHandler() { let largeObject = new Array(1000000).fill("data"); // 创建一个大对象 return function() { console.log("Handler clicked"); // 没有直接使用 largeObject, 但由于闭包的存在, largeObject 无法被回收 }; } document.getElementById("myButton").addEventListener("click", createHandler());在这个例子中,createHandler 函数返回一个事件处理函数(闭包)。这个闭包引用了 createHandler 函数的 largeObject 变量。即使我们没有在事件处理函数中直接使用 largeObject,但由于闭包的存在,largeObject 无法被垃圾回收,导致内存泄漏。 解决方法: 解除引用:在不需要闭包时,手动解除对闭包的引用,例如: let handler = createHandler(); document.getElementById("myButton").addEventListener("click", handler); // ... 当不再需要事件处理程序时 ... document.getElementById("myButton").removeEventListener("click", handler); handler = null; // 解除对闭包的引用避免不必要的闭包:如果不需要访问外部函数的变量,就不要创建闭包。 将变量设置为null: 在闭包中, 将不再需要的外部变量手动设置为null。 图片
-
书接前文 Markdown 进阶玩法 前几天写了一篇关于 Markdown 的科普文章Markdown 基础语法 ⇲,本文继续探讨 Markdown 相关扩展语法。 图片 内嵌HTML标签 Markdown 语法的标记相较于 HTML 还是小菜一碟,当然作为一种写作格式语言,大部分时候是够用的。如果需要进一步优化文字视觉表现力,可以在 Markdown 中内置一些 HTML 和 CSS 样式来改善。 使用时,只需使用 HTML 本身标签即可,无需在其前面添加前缀或分隔符来表明你正在从 Markdown 切换到 HTML。 行内标签 HTML 的行内标签如<span>、<cite>、<del>不受限制,可以在 Markdown 的段落、列表或是标题里任意使用。如果你喜欢,可以直接采用 HTML 标签来格式化。 Less is <strong>more</strong>.(strong 是 HTML 加粗标签)<strong> 标签渲染效果如下: Less is more . 内嵌 CSS 样式 还可以在 Markdown 中嵌入 CSS 样式,和HTML一起使用。 例如,给段落加 CSS 样式: <p style="color:#009;font-style:italic;"></p>换了颜色及倾斜后渲染效果如下: Life is the art of drawing sufficient conclusions form insufficient premises. 区块标签 使用 HTML 区块标签 <div>、<table>、<pre>、<p> 时,必须在前后加上空行与其它内容区隔开,开始标签和结束标签不能用Tab或空格来缩进。 例如在 Markdown 文件里插入 HTML 表格: <table> <tr> <td>Name</td> <td>Age</td> <td>No.</td> </tr> <tr> <td>Tom</td> <td>21</td> <td>01</td> </tr> </table>标签渲染效果如下: Name Age No. Tom 21 01 要注意的是,在 HTML 区块标签间的 Markdown 格式语法将不会被处理。比如在 HTML 区块内使用 Markdown 样式的 *强调* 会没有效果。 插入视频 Markdown 不具有插入视频的功能,好在我们依然可以利用它支持 HTML 标签的特性,用 <video> 标签来插入视频。 视频插入格式如下: <video width="100%" controls src="https://txmov2.a.kwimgs.com/upic/2025/02/14/20/BMjAyNTAyMTQyMDQzMzZfMTMxMzM1NzkxNF8xNTY5NDg0Mzg5NzVfMl8z_b_B7664d41afc4fb15f0f117a1ffe825663.mp4"></video>显示效果如下: 标题 ID 许多 Markdown 编辑器支持标题的自定义 ID,方便直接链接到标题并使用 CSS 对其修改。 书写格式是在标题后边用大括号包裹自定义的 ID 。 ##### Have a nice day {#my-id}对应 HTML 是这样的: <h5 id="my-id">Have a nice day</h5><h5> 标签渲染效果如下: Have a nice day页内锚点跳转 利用指定标题 ID ,通过链接格式可实现页面内目录跳转,链接锚点会自动滚动到屏幕顶端。 把指定 ID 放在标题后面,注意大括号左边的空格不可少。 ### Test title {#custom} [Jump here](#custom)如果 Markdown 工具不支持上述 {#custome} 语法(比如MarktText),还可以使用 span 标签,为元素添加 id 来实现。 <span id ="custom">Test title</span> [Jump here](#custom)跳转渲染效果如下: Test title Jump here 任务列表 创建带有复选框的 TODO List 任务列表,请在任务列表前面添加破折号-和方括号[ ],注意,破折号和方括号之间,以及方括号里面要加空格。选择哪个复选框,就在方括号[x]里面添加 x 。 - [x] This is the first one - [ ] This is the first two复选框渲染效果如下: [x] This is the first one [ ] This is the first two 定义列表 简单来说,就是对多个术语的定义和描述。要创建定义列表,请在第一行上键入术语。在下一行,输入一个冒号,后跟一个空格和详细定义。 Frist List : This is the List Description Second List : This is another List Description对应 HTML 像这样: <dl> <dt>Frist List</dt> <dd>This is the List Description</dd> <dt>Second List</dt> <dd>This is another List Description</dd> </dl>渲染效果如下: Frist List This is the List Description Second List This is another List Description 围栏代码块 基本 Markdown 语法允许你通过缩进四个空格或一个制表符来创建代码块,如果觉得不方便,可以尝试用围栏代码块。 在代码块前后使用三个反引号`,或三个波浪号~~~。 \```json { "firstName": "John", "lastName": "Smith", "age": 25, } \```如果想让代码高亮显示,在代码块的反引号后面指定一种语言,比如 Java: \```java System.out.println(Hello World); \```渲染效果如下: System.out.println(Hello World);表格 在 Markdown 基础篇里我们介绍了创建表格的方法,这里再扩展一下表格的样式。 单元格宽度可以通过横向连字符--自由控制。 | No. | Age | Time | | --| ------- | -------- | | 18 | 24 | 2025.01.21 |如下所示,渲染效果看起来相同。 No.AgeTime18242025.01.21在连字符---左侧、右侧或两侧添加冒号:,来控制列表文本左、右、中对齐。 | No. | Name | Birthday | | :-- | :-----: | ------------: | | 18 | 24 | 08.18 | 渲染效果如下: No.NameBirthday182408.18Emoji表情 有两种方法可以将表情符号添加到 Markdown 文本中,一是从 emojipedia 网站上复制表情符号并粘贴到文本中,另外一种是直接输入 emoji shortcodes,使其包裹在两个冒号中间。 *刚出去散步* :Walking: *看见了一只猫咪* :cat:表情符号渲染效果如下: 刚出去散步 🚶♂️ 看见了一只猫咪 🐱 反斜杠转义 有时候会希望插入一些符号而不想被当作 Markdown 标记渲染,就需要对这些符号进行转义。方法是,在字符前面添加反斜杠字符\。 例如,我想用星号*加在文字旁边做强调效果,可以这样写: \* Are you OK?渲染效果如下: * Are you OK? 可转义的字符 Markdown 支持以下这些符号前面加上反斜杠,从而达到转义目的。 \ backslash ` backtick * asterisk _ underscore {} curly braces [] square brackets () parentheses # hash mark + plus sign - minus sign (hyphen) . dot ! exclamation mark特殊字符自转义 在 HTML 中,有两个字符需要特殊处理:< 和 &。左尖括号用于开始标记;& 符号用于表示 HTML 实体。如果要将它们用作文字字符,则必须将它们转义为实体,例如 < 和 &。 比如你想写关于“AT&T”的内容,你需要写“AT&T”。还需要在 URL 中转义&字符,如果你想链接到: ...&q=larry+bird必须将 URL 编码为: ...&q=larry+bird才能放到标签 href 属性中,这很容易被忘记。Markdown 允许你直接使用这些符号,并帮你自动处理所有必要的转义。如果你使用&符号作为 HTML 实体的一部分,它将保持不变,否则它将被翻译成&。 因此,如果想在文章中包含版权符号,可以这样写: © 印迹说(符号代码 ©)Markdown 不会对它做修改,但如果你写: AT&TMarkdown 会将其翻译为: AT&;T类似地,由于 Markdown 支持行内 HTML,如果你使用尖括号<作为 HTML 标签的分隔符,Markdown 不会对其做任何转义,但如果你这样写: 4 < 5Markdown 会将其翻译为: 4 < 5另外要注意的是,在 Markdown 内联和块元素中,<尖括号和&符号始终会自动编码。这使得使用 Markdown 编写 HTML 代码变得容易(在 HTML 语法中,你要手动把所有的 < 和 & 都转换为 HTML 实体。) 自动 URL 链接 许多 Markdown 编辑器会自动将 URL 或者 email 地址转换为链接,输入网址时,即使没使用尖括号<,Markdown 编辑器也会自动转为可点击链接。 https://mp.weixin.qq.com如果想禁用自动链接 URL,则可以通过反引号`来删除该链接。 `https://mp.weixin.qq.com`脚注 脚注用于添加注释和参考来源,添加脚注时,带有脚注的上标数字会出现在添加脚注参考的位置。这样做的好处是,能保持文档的整洁性。 创建方法是,在方括号内[^1]添加插入符号和标识符,标识符可以是数字或单词,但不能包含空格或制表符。 [^1]: This is the first footnote. [^2]: This is the second footnote.Markdown 语法的最大灵感来源是纯文本电子邮件的格式,旨在尽可能地易于阅读和易于编写。因此,Markdown 的语法完全由标点符号组成,这些标点符号经过精心挑选,以使其看起来像它们的意思。 由于公众号并不能完全兼容 Markdown 所有标记语法,导致一些演示效果与实际效果有细微差异,还由于不能插入外部链接,有一些语法不能完整呈现,不过并不影响作为 Markdown 备忘录学习。
-
PHP 8.4 新特性:属性钩子实用指南 (2025) PHP 8.4 引入了一项名为 Property Hooks 的创新功能,它将彻底改变开发者处理类属性的方式。这种突破性的特性以更优雅、更强大的语法替代了传统的 getter 和 setter 方法,不仅简化了属性访问控制,还确保了代码的简洁性和可维护性。 图片 理解属性钩子: 属性钩子是一种用于拦截属性访问和修改的特殊方法。相比于传统的 getter 和 setter,属性钩子提供了一种更直接、更直观的方式来管理类属性,并且内置了类型安全和验证机制,能更流畅地控制属性交互。 属性钩子的主要优势: 简化语法: 消除冗余的 getter 和 setter 方法,代码更简洁。 增强封装: 对属性访问进行更严格的控制,提高代码安全性。 提升类型安全: 内置类型检查机制,减少运行时错误。 优化性能: 通过更高效的验证方式,实现更快的属性访问。 实际应用 让我们通过一个实际的例子来深入了解属性钩子的强大之处。假设我们有一个 BankAccount 类,需要对账户余额进行复杂的管理: class BankAccount { public get float $balance { return $this->_balance * $this->exchangeRate; } public set float $balance { if ($value < 0) { throw new InvalidArgumentException('Balance cannot be negative'); } $this->_balance = $value; } private float $_balance = 0; private float $exchangeRate = 1.0; }在这个例子中,balance 属性的属性钩子展示了几个关键特性: 自动货币转换: 通过 exchangeRate 实现自动货币转换。 余额验证: 防止出现负余额,保证数据有效性。 类型安全: 确保余额始终为浮点数类型。 简洁易读: 简化了属性访问方式,代码更清晰。 真实场景:电子商务产品定价管理 另一个常见的应用场景是在电子商务应用中管理产品的价格: class Product { public get float $price { return $this->basePrice * (1 - $this->discount); } public set float $price { if ($value <= 0) { throw new InvalidArgumentException('价格必须为正数'); } $this->basePrice = $value; } private float $basePrice = 0; private float $discount = 0; } // 使用示例 $product = new Product(); $product->price = 99.99; // 设置基本价格 echo $product->price; // 计算带折扣的价格这个例子展示了属性钩子如何: 实现复杂的定价计算逻辑 强制执行业务规则(例如:确保价格为正数) 提供简洁明了的价格操作接口 属性钩子相比传统方法的优势 传统的 getter 和 setter 方法常常导致: 代码冗长且重复。 可读性降低。 验证逻辑可能不一致。 方法调用会产生额外的性能开销。 属性钩子通过以下方式解决了这些问题: 提供更简洁的语法。 集中管理属性访问逻辑。 维持严格的类型安全。 提供直接的属性访问方式,如同访问普通属性一样。 最佳实践 在实现属性钩子时,请注意以下几点: 适用于复杂属性逻辑:仅在需要复杂处理时使用属性钩子。 确保类型安全:务必进行类型检查,保证数据类型正确。 实施全面验证:对属性值进行充分的验证,防止非法数据。 保持钩子实现简洁明了:保证钩子函数的逻辑清晰,易于理解和维护。 结论 PHP 8.4 中引入的属性钩子,是面向对象编程领域的一项重大进步。它提供了一种更优雅、更强大的类属性管理方式,帮助开发者编写出更易于维护、更具可读性以及更加健壮的代码。 需要注意的是,任何新的语言特性都需要合理运用。属性钩子并非要完全取代传统的 getter 和 setter 方法,而是作为 PHP 开发工具箱中的一个强有力补充,需要开发者根据实际场景灵活选择。
-
16 个 JavaScript 简写神技,代码效率提升 60%! JavaScript 是一门强大且灵活的语言,拥有丰富的特性和语法糖。分享下 16 个最常用的 JavaScript 的简写技巧,掌握它们可以让我们编写出更简洁、更优雅的代码,并显著提升开发效率(增加摸鱼时间)。 图片 1. 三元运算符简化条件判断 // 传统写法 let result; if (someCondition) { result = 'yes'; } else { result = 'no'; } // 简写方式 const result = someCondition ? 'yes' : 'no';2. 空值合并运算符 // 传统写法 const name = user.name !== null && user.name !== undefined ? user.name : 'default'; // 简写方式 const name = user.name ?? 'default';3. 可选链操作符 // 传统写法 const street = user && user.address && user.address.street; // 简写方式 const street = user?.address?.street;4. 数组去重 // 传统写法 function unique(arr) { return arr.filter((item, index) => arr.indexOf(item) === index); } // 简写方式 const unique = arr => [...new Set(arr)];5. 快速取整 // 传统写法 const floor = Math.floor(4.9); // 简写方式 const floor = ~~4.9;6. 合并对象 // 传统写法 const merged = Object.assign({}, obj1, obj2); // 简写方式 const merged = {...obj1, ...obj2};7. 短路求值 // 传统写法 if (condition) { doSomething(); } // 简写方式 condition && doSomething();8. 默认参数值 // 传统写法 function greet(name) { name = name || 'Guest'; console.log(`Hello ${name}`); } // 简写方式 const greet = (name = 'Guest') => console.log(`Hello ${name}`);9. 解构赋值 图片 10. 字符串转数字 图片 11. 多重条件判断 图片 12. 快速幂运算 图片 13. 对象属性简写 图片 14. 数组映射 图片 15. 交换变量值 图片 16. 动态对象属性 // 传统写法 const obj = {}; obj[dynamic + 'name'] = value; // 简写方式 const obj = { [`${dynamic}name`]: value };欢迎补充。