标签 Web前端 下的文章 - 易航博客
首页
文章分类
源码资源
技术教程
程序软件
文创娱乐
玄学修炼
关于我们
其他页面
网站统计
友情链接
用户留言
高清壁纸
关于易航
热门文章
Joe再续前缘主题 - 本站同款
易航网址导航系统 – 功能强大,轻量易用
Js自动播放HTML音乐(不受浏览器限制,无需先与浏览器交互,无需对浏览器进行修改)
JsonDb-PHP轻量级文件数据库系统
Typecho一键调整网站为冬天情景插件
标签搜索
PHP
网站源码
Web前端
PHP源码
Typecho
课程资料
HTML源码
Typecho插件
武术内功
Joe主题
Web
Android软件
国漫
网络协议
Windows程序
MySQL
Windows
小说
Linux程序
Java源码
发布
登录
注册
找到
25
篇与
Web前端
相关的结果
2024-11-23
15 分钟带你感受 CSS :has() 选择器的强大
最近看到了许多关于 :has() 选择器的知识点,在此总结下来。 MDN 对 :has() 选择器 的解释是这样的: CSS 函数式 伪类 :has() 表示一个元素,如果作为参数传递的任何 相对选择器 在锚定到该元素时,至少匹配一个元素。这个伪类通过把 可容错相对选择器列表 作为参数,提供了一种针对引用元素选择父元素或者先前的兄弟元素的方法。下面一起来感受下 :has() 选择器的强大之处吧。 :has() 选择器选择父元素和前面的兄弟元素 邻接兄弟选择器(+)用来选中恰好处于另一个在继承关系上同级的元素旁边的物件。例如,选中所有紧随<p>元素之后的<img>元素: p + img { }通用兄弟关系选择器(~)用来选中一个元素后面的所有兄弟元素。例如,选中<p>元素之后的所有的<img>元素: p ~ img { }css 并没有提供直接选择父元素或者前面的兄弟元素的选择器,但 :has() 可以做到这点。 1、比如选择所有包含 <p>元素的父元素: :has(p) { }2、选择直接后代元素包含 <p>元素的父元素: :has(> p) { }3、选择直接后代元素包含 <p>元素的父级标签名是 div父元素: div:has(> p) { }4、选择 <p>元素的相邻的前一个标签名是 div的兄弟元素: div:has(+ p) { }5、选择 <p>元素的前面所有标签名是 div的兄弟元素: div:has(~ p) { }:has() 选择器中的 且 和 或 在 :has() 选择器中表示 且 和 或 很简单,例如: p:has(.a):has(.b) 表示选择同时包含子元素 a 和 子元素 b 的 元素 p p:has(.a, .b) 表示选择包含子元素 a 或者包含子元素 b 的 元素 p :has() 选择器选择一个范围内的元素 现在有如下元素 <div> <h2>标题开始(选择第一行字体为绿色,最后一行字体为红色)</h2> <p>h2中间第一行</p> <h4>h2中间第二行</h4> <h5>h2中间最后一行</h5> <h2>标题结束</h2> </div>要求选择第一行字体为绿色,最后一行字体为红色。需要注意的是,中间元素可以是任意的。 cc.png图片 使用 :has() 实现上面效果,可以这么做 /* 选择 h2 中间第一行 */ h2+ :has(~ h2) { color: green; } /* 选择 h2 中间最后一行 */ h2~ :has(+ h2) { color: red; }h2 + :has(~ h2) 表示选择紧跟着 h2 的并且后面还有 h2 元素的兄弟元素。也就选择到了 h2 范围内的第一个元素。 h2 ~ :has(+ h2) 表示选择 h2 后面的兄弟元素,并且该兄弟元素的下一个兄弟元素是 h2,也就选择到了 h2 范围内最后一个元素 那如果要选择中间所有元素呢,可以这样做 dd.png图片 /* 选择 hr 中间所有行 */ hr~ :has(~ hr) { color: blue; }:has()选择器的应用 1、CSS :has() 选择器之星级评分 关于星级评分,之前写过一篇文章分享过三种方式使用纯 CSS 实现星级评分。 这里介绍下使用 :has() 选择器 + :not() 选择器 实现星级评分的方式。 星级评分效果包括鼠标滑入和点击,滑入或点击到第几颗星的位置,该位置之前的星高亮,之后的星不高亮或者有高亮的则取消高亮; star.webp图片 html 结构 <div> <input type="radio" name="radio" id="radio1"> <label for="radio1"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"> <path fill="currentColor" d="M283.84 867.84 512 747.776l228.16 119.936a6.4 6.4 0 0 0 9.28-6.72l-43.52-254.08 184.512-179.904a6.4 6.4 0 0 0-3.52-10.88l-255.104-37.12L517.76 147.904a6.4 6.4 0 0 0-11.52 0L392.192 379.072l-255.104 37.12a6.4 6.4 0 0 0-3.52 10.88L318.08 606.976l-43.584 254.08a6.4 6.4 0 0 0 9.28 6.72z"> </path> </svg> </label> <input type="radio" name="radio" id="radio2"> <label for="radio2"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"> <path fill="currentColor" d="M283.84 867.84 512 747.776l228.16 119.936a6.4 6.4 0 0 0 9.28-6.72l-43.52-254.08 184.512-179.904a6.4 6.4 0 0 0-3.52-10.88l-255.104-37.12L517.76 147.904a6.4 6.4 0 0 0-11.52 0L392.192 379.072l-255.104 37.12a6.4 6.4 0 0 0-3.52 10.88L318.08 606.976l-43.584 254.08a6.4 6.4 0 0 0 9.28 6.72z"> </path> </svg> </label> <input type="radio" name="radio" id="radio3"> <label for="radio3"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"> <path fill="currentColor" d="M283.84 867.84 512 747.776l228.16 119.936a6.4 6.4 0 0 0 9.28-6.72l-43.52-254.08 184.512-179.904a6.4 6.4 0 0 0-3.52-10.88l-255.104-37.12L517.76 147.904a6.4 6.4 0 0 0-11.52 0L392.192 379.072l-255.104 37.12a6.4 6.4 0 0 0-3.52 10.88L318.08 606.976l-43.584 254.08a6.4 6.4 0 0 0 9.28 6.72z"> </path> </svg> </label> <input type="radio" name="radio" id="radio4"> <label for="radio4"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"> <path fill="currentColor" d="M283.84 867.84 512 747.776l228.16 119.936a6.4 6.4 0 0 0 9.28-6.72l-43.52-254.08 184.512-179.904a6.4 6.4 0 0 0-3.52-10.88l-255.104-37.12L517.76 147.904a6.4 6.4 0 0 0-11.52 0L392.192 379.072l-255.104 37.12a6.4 6.4 0 0 0-3.52 10.88L318.08 606.976l-43.584 254.08a6.4 6.4 0 0 0 9.28 6.72z"> </path> </svg> </label> <input type="radio" name="radio" id="radio5"> <label for="radio5"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"> <path fill="currentColor" d="M283.84 867.84 512 747.776l228.16 119.936a6.4 6.4 0 0 0 9.28-6.72l-43.52-254.08 184.512-179.904a6.4 6.4 0 0 0-3.52-10.88l-255.104-37.12L517.76 147.904a6.4 6.4 0 0 0-11.52 0L392.192 379.072l-255.104 37.12a6.4 6.4 0 0 0-3.52 10.88L318.08 606.976l-43.584 254.08a6.4 6.4 0 0 0 9.28 6.72z"> </path> </svg> </label> </div>为了使星星有点击效果,利用 radio + label 的方式实现点击效果;label 代表星星。 当点击星星时,高亮当前星星 input:checked+label { color: gold; }当鼠标移入星星时,高亮当前星星,并且该位置之后的星星取消高亮; label:hover { color: gold; &~label { color: #ccc !important; } }让当前位置之前的所有星星也高亮,可以利用 :not ,排除掉当前位置和当前位置之后的星星。 label:not(:hover, :hover ~ *) { color: gold; }并且只有鼠标滑入时添加这些效果。 div:has(label:hover) label:not(:hover, :hover ~ *) { color: gold; }同样,当点击星星时,点亮当前选择的之前所有的星星也如此 div:has(input:checked) label:not(input:checked ~ label) { color: gold; }完整示例 2、CSS :not 和 :has() 模拟 :only-of-type 有下面的 html 结构 <div> <p>第一页</p> <p class="this">第二页</p> <p>第三页</p> <p>第四页</p> </div>要选择类名为 this 的元素,并设置颜色为红色,使用 .this{color:red;} 可以轻松做到。 aa.png图片 如果现在有两个 div 元素块 <div> <p>第一页</p> <p class="this">第二页</p> <p>第三页</p> <p>第四页</p> </div> <div> <p>第一页</p> <p class="this">第二页</p> <p class="this">第三页</p> <p>第四页</p> </div>现要求选择 div 的子元素中只有含有一个类名为 this 的元素(也就是第一个 div 元素块),并且设置其颜色为红色,该怎么做呢? :only-of-type 代表了任意一个元素,这个元素没有其他相同类型的兄弟元素。 但 :only-of-type 判断是否有相同类型的依据是标签名,而不是类名。所以并不能达到想要的效果。 /* 这种写法是无效的,无法判断元素有没有其他相同的类名。 */ .this:only-of-type { color: red; } /* 这种写法是有效的,但判断的是没有相同的 p 的元素,显然无法满足上面的要求,但能匹配下面 ul 中的 p */ p:only-of-type { color: red; }<ul> <li>第一页</li> <li class="this">第二页</li> <li class="this">第三页</li> <p>第四页</p> </ul>而 :has 能做到,要选择前后没有相同类名的元素 ,也就是排除前后的 .this 。 排除前面的 .this /* 表示选择前面没有 .this 的 .this */ .this:not(.this ~) { }排除后面的 .this, /* 表示排除后面有 .this 的 .this */ .this:not(:has(~ .this)) { }两个做并集,也就选择到了唯一的 .this .this:not(:has(~ .this)):not(.this ~ *) { color: red; }bb.png图片 完整示例 3、CSS :has() 选择器之模仿 mac 电脑 dock 栏 利用 :has() 可以选择到前面的兄弟元素的特点,还能做出下面的动画效果 aa.gif图片 当鼠标滑入到一个元素时,该元素放大,该元素的前一个元素和后一个元素缩小,除了这三个元素之外的其他元素缩的更小并且有一定透明度; html 结构如下 <div class="box"> <div class="son">乔丹</div> <div class="son">科比</div> <div class="son">詹姆斯</div> <div class="son">奥尼尔</div> <div class="son">邓肯</div> <div class="son">卡特</div> <div class="son">麦迪</div> <div class="son">艾弗森</div> <div class="son">库里</div> <div class="son">杜兰特</div> </div>关键 css 代码 .son { ... ... ... &:hover { background-color: #67c23a; transform: scale(1.4); &+.son { transform: scale(1.1); // 后一个相邻的兄弟元素 } } }让前一个元素也缩放为原来的 1.1 /* 选择存在 后一个相邻的被hover的兄弟元素 的元素 */ .son:has(+ .son:hover) { transform: scale(1.2); }然后对这三个元素之外的其他元素缩放为原来的 0.8 .box:has(.son:hover) .son:not(:hover, :has(+ :hover), .son:hover + *) { transform: scale(0.8); opacity: 0.7; }.box:has(.son:hover) 表示选择子元素 son 被 hover 时的 .box .son:not(:hover, :has(+ :hover), .son:hover + *) 表示排除 son 元素里面被 hover 的元素,被 hover 的元素的前一个邻接的兄弟元素,被 hover 的元素的后一个邻接的兄弟元素; 完整示例 4、CSS :has() 选择器之单选题 bb.gif图片 这是个有趣的应用,当选择的是错误的选项时,选择题的标题和当前选择项标红。并且会给正确的选项添加动画效果提示用户这才是正确选项。 这里用 data-correct="false" 表示错误的选项,data-correct="true" 表示正确的选项。 <input type="radio" name="option" data-correct="false" id="option1" /> <label for="option1">Responsive design</label> <input type="radio" name="option" data-correct="true" id="option2" /> <label for="option2">Responsive design</label> <input type="radio" name="option" data-correct="false" id="option3" /> <label for="option3">Responsive design</label>选择错误选项时,标红当前选项。选择正确选项时标绿当前选项。 .question { --correct: #5ed235; /* 正确选项的颜色 */ --wrong: #f83d56; /* 错误选项的颜色 */ --wrong-bg: rgba(248, 61, 86, 0.8); --correct-bg: rgb(94, 210, 53, 0.8); } input[data-correct="false"]:checked+label { color: #fff; background-color: var(--wrong); border-color: var(--wrong); } input[data-correct="true"]:checked+label { color: #fff; background-color: var(--correct); border-color: var(--correct); }选择错误选项时,标红标题; 这里用 :has 选择器获取子元素中有错误选项选中时。 .question:has(input[data-correct="false"]:checked) { .questionHeader { box-shadow: inset 0 7px 0 0 var(--wrong); background-color: var(--wrong-bg); } }并且给正确选项增加提示动画 .question:has(input[data-correct="false"]:checked) { input[data-correct="true"]+label { animation: flash 2s infinite; } } @keyframes flash { 0% { background-color: white; } 25% { background-color: #5ed235; } 50% { background-color: white; } 75% { background-color: #5ed235; } 100% { background-color: white; } }选择正确选项时,标绿标题; .question:has(input[data-correct="true"]:checked) { .questionHeader { box-shadow: inset 0 7px 0 0 var(--correct); background-color: var(--correct-bg); } }完整示例 总结 本文介绍了 :has()选择器的基本用法以及四个实际应用; 选择父元素和前面的兄弟元素 :has() 选择器中的 且 和 或 选择一个范围内的元素 在 :has()选择器出来之前,使用 CSS 是无法直接选择到父级元素和前面的兄弟元素的,但 :has()选择器的出现使这个变成了可能; 如果对本文感兴趣或对你有帮助,麻烦动动你们的发财手,点点赞~
技术教程
# Web前端
易航
11月23日
0
40
0
2024-11-22
浏览器Audio音频自动播放为什么会失效
背景 某天客户报了一个问题,说是大屏的声音不能自动播放了,我们的大屏应用是有报警的,当有报警的时候,会自动播放报警的声音 复线步骤 测试结果如下 当浏览页面后,音频不会自动播放 当从另外的一个页面进入到当前页面,可以直接播放声音 如果你想测试,可以点我进行测试 你可以先点击上面链接的 「尝试一下」,下面为截图 图片 这个时候你会听到一声马叫声 然后,你刷新下一个马叫声的页面,这个时候声音的自动播放将不会生效 图片 报错问题排查 打开控制台,无法意外看到一个报错信息。 图片 翻译为中文的意思为允许的错误。播放失败,因为用户没有先与文档交互。https\://goo.gl/xX8pDD 尝试解决 那我就通过给body添加点击事件,自动触发点击事件,在点击的事件后自动播放声音。(当是我的想法是,这个大概率是不行的,chrome应该不会这个忽略点,不然这个功能就外表不存在) 经过测试后,发现确实还不行,在意料中。 参考别人的网站,用抖音测试 点击我跳转抖音 想到了我们可以参考抖音,我用抖音进行测试,当你不应该做任何操作时,页面如下 图片图片 我们从这里总结得出的结论,这应该是浏览器的,需要查看官方文档,看看原因 刊物 点我查看chrome的官方文档 「我截取了一些关键信息」 图片图片 注意浏览器有一个「媒体互动指数」,这是浏览器自动计算的,该分结果,才会触发自动播放 「查看电脑的媒体互动指数」 在url上输入about://media-engagement,你会看到如下的截图, 图片图片 「经过测试后」当网站变成了「High」,音频会自动播放,不会播放失败。 这里解释了为什么有的网站可以自动播放声音,有的网站不可以自动播放声音 好吧,我们继续往下看,这个时候看到了一些关键的信息。 「作为人,我们不应该相信音频开发/视频播放会成功,要始终在播放的回落中来进行判断」 图片图片 看到这些,我们来修改抖音的实现。在播放声音的catch的时候,显示一个错误的弹窗,提示用户,当用户点击的时候,自动播放声音 this.alarmAudio = new Audio(require("@/assets/sound/alarm.mp3")); this.alarmAudio .play() .then(() => { this.notifyId && this.notifyId.close(); }) .catch((error) => { if (error instanceof DOMException) { // 这里可以根据异常类型进行相应的错误处理 if (error.name === "NotAllowedError") { if (this.notifyId) return; this.notifyId = Notification({ title: "", duration: 0, position: "bottom-left", dangerouslyUseHTMLString: true, onClick: this.onAudioNotifyConfirm, showClose: false, customClass: "audio-notify-confirm", message: "<div style='color:#fff;font-size:18px;cursor:pointer'>因浏览器限制,需<span style='color:#ff2c55'>点击打开声音</span></div>", }); } } });实现效果如下 图片图片 总结 在启用视频或者音频的时候,要始终不相信他会播放声音成功,并且添加catch处理异常场景,给用户友好的提示 或者视频音频的自动播放跟媒体互动指数有关(MEI),当媒体指数高,会自动播放,否则需要用户先交互后,音频才可以自动播放。 从一个页面window.打开另外一个页面可以自动播放声音,当刷新页面后,需要有高的MEI,音频才会自动播放,如果你需要在后台打开一个大屏的页面,正好可以这样设计,不要用页面跳转
技术教程
# Web前端
易航
11月22日
0
34
0
2024-11-13
一款功能丰富、界面美观的OA办公系统
介绍 OA-System Vue 开发的OA系统 具有工作流动态审批、加签、会签等工作流功能 具有文档预览、图片预览等功能 具有博客编写、预览、查看、搜索等功能 具有社区、问答等功能 具有OA系统常用功能 具有在线网盘等功能 支持审批流程、自由流程,审批日志,我的待办,我的已办,行政公告,Office文档预览,文档转PDF,图片压缩。 功能一览 具有工作流动态审批、加签、会签等工作流功能,可以对工作流程的审批业务进行评论/讨论 具有文档预览、图片预览等功能 具有博客编写、预览、查看、搜索等功能 具有社区、问答等功能 具有OA系统常用功能 具有在线网盘等功能 具有OA的移动端应用 工作流引擎完全手写且开源,可以类似钉钉/飞书那样,动态选择审批人员。 项目截图 图片图片 图片图片 图片图片 图片图片 图片图片 图片图片 图片图片 图片图片 图片图片 源码下载 隐藏内容,请前往内页查看详情
源码资源
# 网站源码
# Web前端
# NodeJs
易航
11月13日
10
167
0
2024-11-12
CSS 让 height 高度属性完美支持 auto 过渡动画
众所周知,有些属性是不支持过渡动画的,比如高度 auto div{ height: 0; transition: 1s } .wrap:hover div{ height: auto }效果如下 图片 要实现过渡效果,之前提供过一个 grid 布局方式,原理是利用 grid 的尺寸单位 1fr 支持过渡的特性 一、calc-size 函数 现在要实现 auto 的过渡效果,需要用到一个全新的 calc-size 函数 图片 看到这个函数,是不是和 calc 比较类似?没错,这是一个可以将一些关键词转换成具体尺寸的函数。 回到上面这个例子,只需要将高度改成 calc-size(auto) ,如下 div{ height: 0; transition: 1s } .wrap:hover div{ height: calc-size(auto) }现在就有过渡效果了(Chrome 129+ 或者 Chrome 127+开启实验属性) 图片 其实除了 auto ,还支持其他尺寸关键词,比如 height: calc-size(min-content) height: calc-size(max-content) height: calc-size(fit-content)也支持混合计算,如下 height: calc-size(auto + 10px) height: calc-size(max-content - 10px)二、interpolate-size 属性 前面的例子,为了兼容之前的浏览器,还必须保留 height: auto 的写法 div{ height: 0; transition: 1s } .wrap:hover div{ height: auto; height: calc-size(auto) }如果是已经存在的项目,可能会有很多地方需要都要改成这种写法,有一定的侵入性。 为此,浏览器还提供了一个 interpolate-size 属性,这个属性可以设置插值计算的规则,有两个关键词 interpolate-size: numeric-only;/*默认值*/ interpolate-size: allow-keywords;其中第一个 numeric-only ,表示仅限数值,也就是只有真实的数值才会有过渡效果(目前浏览器的默认效果),第二个 allow-keywords 表示允许所有关键词,当然包括 auto 属性 有了这个属性,要做的事情就更简单了,只需要在全局 :root 加上这个属性 :root{ interpolate-size: allow-keywords; } div{ height: 0; transition: 1s } .wrap:hover div{ height: auto; }这样就全局生效了,无需在每个地方就加上 calc-size(auto) ,是不是非常方便呢? 图片 三、也支持 detail 展开过渡 大家可能都知道,detail 配合 summary 可以实现展开折叠效果 <div class="con"> <details name="a"> <summary>分组A</summary> <p>这是第一个分组 name="a"</p> </details> <details name="a"> <summary>欢迎</summary> <p>最近 details元素新增了一个name属性</p> </details> <details name="a"> <summary>关注</summary> <p>别看这只是一个普普通通的属性,这可是带来了一个全新的模式,一起了解一下吧</p> </details> </div>效果如下 图片 当然默认展开折叠是没有过渡效果的 利用 calc-size 或者 interpolate-size 也可以很轻松的实现过渡动画,关键实现如下 :root { interpolate-size: allow-keywords; } ::details-content{ content-visibility: visible; height: 0; transition: .3s; overflow: hidden; } details[open]::details-content{ height: auto; }这样就有过渡效果了,非常丝滑 图片 这是一段通用代码,可以用在任何地方 四、现在其实可以用起来了 虽然说兼容性很差(Chrome 129+),但这是一个渐进增强属性,不会影响现有功能,也无需修改已有结构,只需要全局增加这样一行就行了 :root { interpolate-size: allow-keywords; }这样能支持的浏览器自然就会有过渡动画了,完全不用担心是否兼容。 总结一下,其实就两点 calc-size 可以将非数值类型的单位转换成支持过渡的尺寸单位,包括 auto interpolate-size 可以从全局范围允许任意关键词支持过渡
技术教程
# Web前端
易航
11月12日
0
117
2
2024-11-09
Three.js 可滑动魔方源码
图片 html 部分 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>魔方</title> <meta name="viewport" content="width=device-width,height=device-height,user-scalable=no,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0"> <link rel="stylesheet" href="css/style.css"> </head> <body> <div class="mofang"> <div class="mofang__background"></div> <div class="mofang__game"></div> <div class="mofang__texts"> <h1 class="text text--title"> <span>魔方</span> </h1> <div class="text text--note"> 双击即可开始 </div> <div class="text text--timer"> 0:00 </div> <div class="text text--complete"> <span>完成!</span> </div> <div class="text text--best-time"> <icon trophy></icon> <span>最佳时间!</span> </div> </div> <div class="mofang__prefs"> <range name="flip" title="翻转类型" list="迅速的 ,平滑的,弹起"></range> <range name="scramble" title="扰乱长度" list="20,25,30"></range> <range name="fov" title="摄像机角度" list="摄影,透视的"></range> <range name="theme" title="配色方案" list="灰色,浅蓝色,浅黄色,脏黄色,淡青色"></range> </div> <div class="mofang__stats"> <div class="stats" name="total-solves"> <i>全部解决:</i><b>-</b> </div> <div class="stats" name="best-time"> <i>最佳时间:</i><b>-</b> </div> <div class="stats" name="worst-time"> <i>最差时间:</i><b>-</b> </div> <div class="stats" name="average-5"> <i>平均值 5:</i><b>-</b> </div> <div class="stats" name="average-12"> <i>平均值 12:</i><b>-</b> </div> <div class="stats" name="average-25"> <i>平均值 25:</i><b>-</b> </div> </div> <div class="mofang__buttons"> <button class="btn btn--bl btn--stats"> <icon trophy></icon> </button> <button class="btn btn--bl btn--prefs"> <icon settings></icon> </button> <button class="btn btn--bl btn--back"> <icon back></icon> </button> <a href="#" class="btn btn--br btn--pwa"> </button> </div> </div> <script src='https://cdnjs.cloudflare.com/ajax/libs/three.js/95/three.min.js'></script> <script src="js/common.js"></script> </body> </html>完整项目地址 隐藏内容,请前往内页查看详情
免费资源
源码资源
# Web前端
易航
11月9日
2
41
0
2024-11-08
JavaScript逆向系列 09-Js Hook
0x00 前言 缘起是我前两天看了一篇逆向文章,里面用到了一段hook脚本,在这之前我是不理解hook是什么东西,看了那段脚本后我突然就悟了,遂写下这篇文章分享一下个人心得。 注:本文不会太深入js hook。 0x01 Intro 首先我需要明确一点,我们在浏览网站时,由于js是在客户端上执行的,所以我们有最高的权限,这也就方便我们去对js进行一些操作,例如hook。我个人认为的js hook技术就是我们去修改函数或方法内部的实现过程,也就是重写方法,以便我们去利用它去实现一些我们想要的效果。 接下来我会通过一个小demo简单演示一下js hook脚本该如何编写。 0x02 Demo console.log = function (message) { alert(message); }效果: 图片图片 console是内置对象,不需要实例化即可使用,所以我们可以直接修改它的方法,例如log方法。代码中我将log方法的内部实现过程改成了将传入的参数进行alert。不过这个脚本其实还是有缺陷的,一般情况下我们改写某个函数或方法的内部实现过程后,我们还需要将它原本的功能实现了,否则可能会造成意想不到的后果。 改写后的脚本: var test = console.log; console.log = function (message) { alert(message); test(message); }将log方法赋值给test,代码执行完我们想要的效果后就完成它本来的工作,也就是最后执行test函数,相当于执行了log方法。 效果: 图片图片 图片图片 现在就是一个比较完善的hook脚本了。 0x03 个人脚本分享 我在看完上文提到的那篇逆向文后,立马就去写了我的第一个hook脚本(注:后文会发全部代码以及讲解如何使用): 图片图片 就拿上期自动化加解密的案例进行测试: 图片图片 图片图片 通过控制台输出的堆栈信息直接定位到解密位置。 我先说明一下我为什么要重写JSON.parse和JSON.stringify这两个方法,可能有看过我的逆向文章或者看过其他js逆向文章的朋友们会发现,这两个方法在加解密操作中出场率极高。一般情况下密文解密后开发可能会选择将json转为object,那么就会用到JSON.parse,JSON.stringify可能就会在加密时用到。 代码的话通过上文的讲解读者应该能看懂大部分,我觉得唯一需要讲的就是new Error().stack,Error是构造函数,需要实例化才能用,以下是MDN介绍的stack方法:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Error/stack 图片图片 简单来说就是它可以直接输出调用的堆栈,也就是上文演示的效果: 图片图片 不过我这里还需要提的一点的就是这个方法需要不断的实例化调用,如果只实例化一个对象然后反复调用这个实例的stack方法,只会输出实例化时的那个调用堆栈,例如: 图片图片 图片图片 0x04 如何使用js hook脚本 当我们要hook时,一般来说这个脚本一定要是文档中第一个加载执行的js,这样就能拿到函数或方法的控制权,所以我们就需要插件进行帮助。 这里我推荐大家使用油猴插件,直接在google应用商店搜篡改猴即可: 图片图片 安装后固定到chrome后点击添加新脚本: 图片图片 将代码写到注释部分即可: 图片图片 另外我需要提一点,我这个hook脚本一定要是文档中第一个加载的js,所以要修改一下脚本的运行时期。保存代码后点击设置: 图片图片 图片图片 修改运行时期即可,document-start是我们需要设置的: 图片图片 具体为什么可查看油猴中文文档(https://www.cnblogs.com/grubber/p/12560522.html): 图片图片 hook_JSON: // ==UserScript== // @name hook_JSON // @namespace http://tampermonkey.net/ // @version 2024-10-29 // @description try to take over the world! // @author 0xsdeo // @match http://*/* // @icon https://www.google.com/s2/favicons?sz=64&domain=csdn.net // @grant none // ==/UserScript== (function() { 'use strict'; var json_p = JSON.parse; JSON.parse = function(str){ console.log(str); console.log(new Error().stack); console.log("-----------------------------------------------------------------------------------------------------") return json_p(str); } var json_s = JSON.stringify; JSON.stringify = function(obj){ console.log(obj); console.log(new Error().stack); console.log("-----------------------------------------------------------------------------------------------------") return json_s(obj); } })();最后提一点,脚本需要指定一下要执行脚本的网站,匹配到的网站才会执行脚本,也是在设置里改: 图片图片 这里我设置的*,意为所有网站都执行该脚本。
技术教程
# Web前端
易航
11月8日
0
22
0
2024-11-04
20个超好看又开源的落地页/首页模板(附源码)
分享 20 个超好看的落地页/首页模板。 模板预览 nefa 图片图片 trippi 图片图片 tailwind-landing-page-template 图片图片 vivid-landing-template 图片图片 shadcn-landing-page 图片图片 open-react-template 图片图片 skilline-landing-page 图片图片 template-landing-page 图片图片 SaaS-Boilerplate 图片图片 nextly-template 图片图片 fresh 图片图片 landing 图片图片 nutritrack 图片图片 mylandingpage 图片图片 React-Landing-Page-Template 图片图片 landy-react-template 图片图片 landing-template-nextui 图片图片 next-saas-starter 图片图片 daisyui-nextjs-landing-page 图片图片 react-landing-page-template-2021 图片图片 源码下载 隐藏内容,请前往内页查看详情
免费资源
源码资源
# 网站源码
# Web前端
# HTML源码
易航
11月4日
4
162
0
2024-10-30
HTML+CSS实现太极八卦加载动画
动画效果预览 HTML部分 <html> <head> <meta charset="utf-8"> <title>太极八卦</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="./55-太极八卦.css"> </head> <body> <div class="table"> <div class="table-cell"> <svg width="470px" height="470px" viewBox="0 0 470 470" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <defs> <filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-1"> <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset> <feGaussianBlur stdDeviation="25" in="shadowOffsetOuter1" result="shadowBlurOuter1"> </feGaussianBlur> <feColorMatrix values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.63 0" in="shadowBlurOuter1" type="matrix" result="shadowMatrixOuter1"></feColorMatrix> <feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetInner1"></feOffset> <feGaussianBlur stdDeviation="25" in="shadowOffsetInner1" result="shadowBlurInner1"> </feGaussianBlur> <feComposite in="shadowBlurInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1"></feComposite> <feColorMatrix values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.7 0" in="shadowInnerInner1" type="matrix" result="shadowMatrixInner1"></feColorMatrix> <feMerge> <feMergeNode in="shadowMatrixOuter1"></feMergeNode> <feMergeNode in="SourceGraphic"></feMergeNode> <feMergeNode in="shadowMatrixInner1"></feMergeNode> </feMerge> </filter> <filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-2"> <feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset> <feGaussianBlur stdDeviation="22.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"> </feGaussianBlur> <feColorMatrix values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.7 0" in="shadowBlurOuter1" type="matrix" result="shadowMatrixOuter1"></feColorMatrix> <feMerge> <feMergeNode in="shadowMatrixOuter1"></feMergeNode> <feMergeNode in="SourceGraphic"></feMergeNode> </feMerge> </filter> <filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-3"> <feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset> <feGaussianBlur stdDeviation="20" in="shadowOffsetOuter1" result="shadowBlurOuter1"> </feGaussianBlur> <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.7 0" in="shadowBlurOuter1" type="matrix" result="shadowMatrixOuter1"></feColorMatrix> <feMerge> <feMergeNode in="shadowMatrixOuter1"></feMergeNode> <feMergeNode in="SourceGraphic"></feMergeNode> </feMerge> </filter> <filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-4"> <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset> <feGaussianBlur stdDeviation="25" in="shadowOffsetOuter1" result="shadowBlurOuter1"> </feGaussianBlur> <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.63 0" in="shadowBlurOuter1" type="matrix" result="shadowMatrixOuter1"></feColorMatrix> <feMerge> <feMergeNode in="shadowMatrixOuter1"></feMergeNode> <feMergeNode in="SourceGraphic"></feMergeNode> </feMerge> </filter> <filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-5"> <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset> <feGaussianBlur stdDeviation="15" in="shadowOffsetOuter1" result="shadowBlurOuter1"> </feGaussianBlur> <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.23 0" in="shadowBlurOuter1" type="matrix" result="shadowMatrixOuter1"></feColorMatrix> <feMerge> <feMergeNode in="shadowMatrixOuter1"></feMergeNode> <feMergeNode in="SourceGraphic"></feMergeNode> </feMerge> </filter> <filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-6"> <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset> <feGaussianBlur stdDeviation="25" in="shadowOffsetOuter1" result="shadowBlurOuter1"> </feGaussianBlur> <feColorMatrix values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.63 0" in="shadowBlurOuter1" type="matrix" result="shadowMatrixOuter1"></feColorMatrix> <feMerge> <feMergeNode in="shadowMatrixOuter1"></feMergeNode> <feMergeNode in="SourceGraphic"></feMergeNode> </feMerge> </filter> <filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-7"> <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset> <feGaussianBlur stdDeviation="15" in="shadowOffsetOuter1" result="shadowBlurOuter1"> </feGaussianBlur> <feColorMatrix values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.23 0" in="shadowBlurOuter1" type="matrix" result="shadowMatrixOuter1"></feColorMatrix> <feMerge> <feMergeNode in="shadowMatrixOuter1"></feMergeNode> <feMergeNode in="SourceGraphic"></feMergeNode> </feMerge> </filter> </defs> <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> <g id="Artboard-1"> <ellipse id="Oval-1" fill="#485d51" cx="237" cy="228" rx="111" ry="111"></ellipse> <circle id="Oval" fill="#0E7CFE" filter="url(#filter-1)" cx="237" cy="228" r="39"></circle> <path d="M237.737045,228.155741 C206.543902,228.155741 181.166785,253.532859 181.166785,284.726749 C181.166785,312.174294 200.823516,335.102165 226.795386,340.215844 C169.77682,334.873529 125,286.749357 125,228.358226 C125,166.403809 175.404556,116 237.357479,116 C241.130723,116 242.479377,116.122537 242.479377,116.122537 C271.062631,118.710011 293.460007,142.732496 293.460007,171.989704 C293.460007,227.891241 237.737045,228.155741 237.737045,228.155741 L237.737045,228.155741 Z" id="Path1" fill="#FFFFFF" filter="url(#filter-2)"></path> <g id="Group" transform="translate(264.500000, 228.500000) scale(-1, -1) translate(-264.500000, -228.500000) translate(180.000000, 116.000000)" filter="url(#filter-3)" fill="#000000"> <path d="M112.737045,112.155741 C81.5439023,112.155741 56.1667848,137.532859 56.1667848,168.726749 C56.1667848,196.174294 75.8235156,219.102165 101.795386,224.215844 C44.7768195,218.873529 0,170.749357 0,112.358226 C0,50.403809 50.4045562,-2.84217094e-14 112.357479,-2.84217094e-14 C116.130723,-2.84217094e-14 117.479377,0.122537018 117.479377,0.122537018 C146.062631,2.71001075 168.460007,26.7324965 168.460007,55.9897038 C168.460007,111.891241 112.737045,112.155741 112.737045,112.155741 L112.737045,112.155741 Z" id="Path2"></path> </g> <circle id="Oval-3" fill="#000000" filter="url(#filter-4)" cx="164" cy="156" r="39"></circle> <circle id="Oval-3-2" fill="#000000" filter="url(#filter-5)" cx="187" cy="83" r="16"></circle> <circle id="Oval-4" fill="#FFFFFF" filter="url(#filter-6)" cx="309" cy="300" r="39"></circle> <circle id="Oval-4-2" fill="#FFFFFF" filter="url(#filter-7)" cx="286" cy="373" r="16"></circle> </g> </g> </svg> </div> </div> <a class="box-item" href="https://codepen.io/LOverride/" target="_blank"> </a> </body> </html>CSS部分 隐藏内容,请前往内页查看详情
技术教程
# Web前端
易航
10月30日
2
53
1
2024-10-30
2024 年最前沿的 5 大 CSS 功能 | 高级 CSS
CSS作为Web设计的基石,一直在不断进化,以应对现代设计的挑战。2024年,CSS引入了一系列令人惊叹的新特性,大大拓展了Web设计的可能性。本文将深入探讨五个最具革命性的CSS新特性,这些特性正在彻底改变前端开发的方式。 1.CSS容器查询(Container Queries) 容器查询允许基于元素的容器大小而非视口来设置样式,这对响应式设计是一个巨大的突破。 示例: 图片 这种方法使得组件级别的响应式设计成为可能,大大提高了代码的可维护性和模块化程度。 2.CSS子网格(Subgrid) 子网格是CSS网格布局的扩展,允许网格项继承其父元素的网格定义。这对于复杂的嵌套布局特别有用。 在 subgrid 出现之前,我一直在为嵌套网格而苦苦挣扎,这往往会导致 CSS 变得复杂冗长。 子网格允许子元素与父网格无缝对齐,从而简化了这一过程。 示例: 图片 子网格简化了复杂布局的创建,减少了冗余代码,提高了网格设计的一致性。 3.@property规则定义的CSS自定义属性 @property规则允许定义具有类型检查、初始值和继承特性的自定义属性(CSS变量)。 示例: 图片 这种方法增强了CSS变量的能力,提供了更多对其行为的控制,确保了它们的正确使用。 4.CSS嵌套 CSS嵌套允许以反映HTML结构的方式嵌套CSS选择器,提高了CSS的可读性和可维护性。 示例: .card { background: white; & .title { color: black; } & .content { font-size: 0.9em; } }这种特性使CSS更加组织化,简化了样式的编写和维护过程,特别是在大型项目中。 5.CSS滚动链接动画 滚动链接动画允许创建响应用户滚动位置的动画,为网站增添了新的交互维度。 示例: @keyframes fade-in { from { opacity: 0; } to { opacity: 1; } } #box { animation: linear fade-in; animation-timeline: scroll(); }这种动画可以使网站更加动态和吸引人,增强用户体验。 结语 2024年的这些CSS新特性为创建更具响应性、组织性和吸引力的Web设计提供了强大的工具。通过在工作流程中incorporate这些前沿特性,开发者可以显著提升项目质量并简化开发过程。 这些新特性不仅提高了开发效率,还开启了Web设计的新可能性。例如,容器查询使得真正的组件级响应式设计成为现实,而滚动链接动画则为用户交互带来了新的维度。随着这些特性的广泛采用,Web开发的未来将更加灵活、高效且富有创意。 掌握这些新特性,将有助于开发者在不断演进的Web开发世界中保持领先地位。通过实践和探索这些新工具,开发者可以创造出更加动态、响应迅速且视觉吸引的Web体验。
技术教程
# Web前端
易航
10月30日
0
45
0
1
2
3
下一页
易航博客