REC
首页
文章分类
源码资源
技术教程
程序软件
文创娱乐
玄学修炼
关于我们
其他页面
网站统计
友情链接
用户留言
高清壁纸
关于易航
热门文章
Joe再续前缘主题 - 搭建本站同款网站
易航网址导航系统 – 功能强大,轻量易用
JsonDb-PHP轻量级文件数据库系统
Typecho一键调整网站为冬天情景插件
V免签全开源免签约码支付系统(支持:支付宝 微信 QQ)
标签搜索
PHP
Web前端
网站源码
PHP源码
Typecho
Typecho插件
课程资料
Windows程序
Android软件
武术内功
HTML源码
Web
Joe主题
Python
Windows
国漫
网络协议
MySQL
NodeJs
小说
发布
登录
注册
找到
145
篇与
技术教程
相关的结果
- 第 5 页
2025-01-08
getHTML() - 替代 innerHTML 的最佳方法
随着所有主流浏览器现已支持 getHTML() 方法,前端开发者有了一个强大的新工具来操作DOM。本文主要探讨 getHTML()的独特优势,特别是在处理Shadow DOM时的卓越表现。 getHTML()与innerHTML的异同 getHTML()和 innerHTML 的 getter 在基本功能上相似,都返回元素内部DOM树的HTML表示。但getHTML()的真正优势在于它能够包含Shadow DOM的HTML,而innerHTML则完全忽略Shadow DOM。 getHTML()的高级用法 getHTML()接受一个可选的options对象参数,通过适当的选项可以获取完整的HTML,包括Shadow DOM: const container = document.body; const host = createDiv(123); const root = attachShadowDOM(host); container.append(host); console.log(container.getHTML({ shadowRoots: [root] }));图片 这段代码会返回包含声明式Shadow Root的完整HTML: <div> <template shadowrootmode="open"> <p>Paragraph <slot>default</slot></p> </template> 123 </div>如果在浏览器中将返回的 上面的 HTML 作为新页面打开,则会再现原始 DOM 树: 图片 通常,shadow trees和slots是在自定义元素的构造函数中创建的,但为了保持上面和下面示例页面中的代码简单,这里没有创建任何自定义元素。相反,使用了两个辅助函数: // shared.js export function attach(host) { const shadowRoot = host.attachShadow({ mode: 'open' }); shadowRoot.innerHTML = '<p>Paragraph <slot>default</slot></p>'; return shadowRoot; } export function div(n) { const el = document.createElement('div'); if (n) el.innerHTML = n; return el; }div(n)创建一个新的div元素,里面包含数字n,例如<div>123</div>,而attach(host)将HTML为<p>Paragraph <slot>default</slot></p>的shadow树附加到host元素上。为了用常见情况挑战getHTML(),div中的数字123被分配到shadow DOM的slot中。 处理嵌套的Shadow DOM 在上面的页面中,getHTML()被调用时使用了所有两个可能的选项: <script type="module"> import { attach, div } from './shared.js'; const container=document.body; const host=div(123); const root=attach(host); container.append(host); console.log('>innerHTML',container.innerHTML); console.log('>getHTML',container.getHTML()); console.log('>getHTML2',container.getHTML({ serializableShadowRoots: true })); console.log('>getHTML3',container.getHTML({ shadowRoots: [root] })); </script>options对象可以有两个属性:serializableShadowRoots和shadowRoots。 当getHTML()在没有options的情况下被调用时,Shadow DOM会被忽略,就像在innerHTML中一样。 如果serializableShadowRoots为true,HTML将包括具有serializable属性设置为true的shadow roots。这样的roots通常不应该存在,因为serializable是与getHTML()一起引入的,默认情况下它是false。 要获取shadow roots的HTML,需要在shadowRoots属性中提供要序列化的shadow roots。当shadow roots是open的时候,可以很容易地递归检索网页中的所有shadow roots。在网页上下文中无法检索closed shadow roots,但可以在浏览器扩展注入的内容脚本中检索。 提供的shadow roots不一定会被序列化。在下一个示例页面中,创建了两个shadow trees。第二个shadow DOM嵌套在第一个中: <script type="module"> import { attach, div } from './shared.js'; const container=document.body; const host=div(123); const root=attach(host); container.append(host); const host2=div(456); const root2=attach(host2); container.append(host); root.append(host2); console.log('>innerHTML',container.innerHTML); console.log('>getHTML',container.getHTML()); console.log('>getHTML2',container.getHTML({ serializableShadowRoots: true })); console.log('>getHTML3',container.getHTML({ shadowRoots: [root] })); console.log('>getHTML4',container.getHTML({ shadowRoots: [root2] })); console.log('>getHTML5',container.getHTML({ shadowRoots: [root,root2] })); </script>如果第一个shadow DOM不包含在options中,getHTML()不会返回第二个shadow DOM的HTML: 要被序列化,shadow roots需要直接连接到要被序列化的DOM。如果省略了父shadow root,嵌套的shadow root也不会被序列化。 getHTML 局限性 缺少outerHTML等价物:目前还没有获取包含元素自身在内的HTML的方法。 单根元素限制:getHTML()返回的HTML如果没有单一根元素,浏览器可能无法正确解析为声明式Shadow DOM。 封闭的Shadow DOM:在网页上下文中无法获取封闭的Shadow DOM,但可以通过浏览器扩展的内容脚本来实现。 结语 getHTML()为开发者提供了一种强大的方法来处理包含Shadow DOM的复杂DOM结构。虽然它有一些限制,但在处理现代Web组件和复杂UI时,getHTML()的优势是显而易见的。随着Web组件的普及,掌握getHTML()将成为前端开发者的重要技能。 在实际开发中,getHTML()可以用于创建更精确的DOM快照、调试复杂的组件结构,以及在需要保留Shadow DOM结构的情况下序列化页面内容。随着Web标准的不断发展,我们可以期待看到更多类似getHTML()这样的强大API,进一步增强前端开发的能力和灵活性。
技术教程
# Web前端
易航
1月8日
0
24
0
2025-01-08
超高级的CSS印章效果!附源码!!
效果预览 图片 源码 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>印章</title> </head> <body> <canvas id="canvas" width="250" height="250"></canvas> </body> <script> function createSeal(id, company, name) { var canvas = document.getElementById(id); var context = canvas.getContext('2d'); // 绘制印章边框 var width = canvas.width / 2; var height = canvas.height / 2; context.lineWidth = 7; context.strokeStyle = "#f00"; context.beginPath(); context.ellipse(width, height, 110, 80, 0, 0, Math.PI * 2); // 修改为椭圆形 context.stroke(); // 绘制印章中间的文字 context.font = '16px Helvetica'; context.textBaseline = 'middle';//设置文本的垂直对齐方式 context.textAlign = 'center'; //设置文本的水平对对齐方式 context.lineWidth = 1; context.fillStyle = '#f00'; context.fillText('全国二次元聚集地', width, height + 5); // 绘制印章名称 context.font = '20px Helvetica'; context.textBaseline = 'middle';//设置文本的垂直对齐方式 context.textAlign = 'center'; //设置文本的水平对对齐方式 context.lineWidth = 1; context.fillStyle = '#f00'; context.fillText(name, width, height + 55); // 绘制印章单位 context.translate(width, height); // 平移到此位置 context.font = '18px Helvetica'; var count = company.length; // 字数 var angle = 2 * Math.PI / 15; // 修改为围绕椭圆的角度 var radiusX = 86; // 椭圆的X半径 var radiusY = 60; // 椭圆的Y半径 var chars = company.split(""); var c; var startAngle = Math.PI / 1; // 设置开始文字的角度 for (var i = 0; i < count; i++) { c = chars[i]; // 需要绘制的字符 var currentAngle = startAngle + angle * i; // 当前字符的角度 var x = radiusX * Math.cos(currentAngle); // X坐标 var y = radiusY * Math.sin(currentAngle); // Y坐标 context.save(); context.translate(x, y); // 平移到字符位置 context.rotate(currentAngle + Math.PI / 2); // 旋转字符 context.fillText(c, 0, 0); // 绘制字符 context.restore(); } } createSeal('canvas', '全国统一发票监制章', '749局'); </script> </html>
技术教程
# Web前端
易航
1月8日
0
76
0
2025-01-04
用 iframe 必定遇到过这六种“坑”之一(以 vue 为示例)
前言 如果你是做web前端,那么不可避免早晚都会用到iframe的。其实博主很久前用过,但最近又要有项目用了,由于年代久远对iframe的注意事项都有点忘记了,然后想着总结一下比较需要注意的几个重点事项,除了便于高效工作还能分享给有需要用到iframe的小伙伴。 iframe基于父窗口大小自适应宽高 「简述:」 这是iframe最常见的需求了,有时候我们用iframe嵌入一个页面时,不想固定宽高想跟随父系统屏幕大小动态变化,从而大大提高适配性。 「实现思路:」 iframe标签绑定:style 来动态设置宽高,监听父窗口宽高变化时动态获取并且绑定到:style,但监听变化需要考虑到初始化和窗口缩放的情况,并且记得移除事件监听器防止内存泄漏。 「完整实现代码如下所示」 <template> <div class="box" @resize="iframeResize"> <iframe :src="iframeSrc" :style="{ width: '100%', height: frameHeight + 'px' }" ref="myRef"></iframe> </div> </template> <script setup> import { onMounted, onUnmounted, ref, watchEffect } from 'vue'; const myRef = ref(null); const iframeSrc = 'https:******.com'; const frameHeight = ref(0); // 调整iframe的高度的方法 function initHeight() { if (myRef.value) { frameHeight.value = window.innerHeight; } } // 窗口大小变化触发 function iframeResize() { initHeight(); } // 移除事件监听器, 防止内存泄漏 onUnmounted(() => { window.removeEventListener('resize', iframeResize); }); // 在组件挂载时先获取一次iframe高度 onMounted(() => { initHeight(); window.addEventListener('resize', iframeResize); }); // 时刻监听变化,防止iframeRef没有赋值 watchEffect(() => { if (myRef.value) { initHeight(); } }); </script> <style scoped> .box { position: relative; width: 100%; height: 100vh; } </style>iframe基于内容动态宽高 「简述:」 例如我们业务需求嵌入的是一个表格而不是一个页面,并且表格高度并不确定时我们不能固定iframe的高度,否则只有一条内容或者没有内容的时候会不好看,这里要根据内容的数量去决定ifram嵌入窗口的高度。 「实现思路:」 思路是子窗口通信告诉父窗口具体高度,然后父窗口再动态设置高度即可。具体实现是子窗口利用 window.postMessage 来发送具体高度,然后父窗口用window.addEventListener('message', 方法)接收内容,从而根据接收到的内容动态调整iframe的高度。 「子窗口(被嵌入页面)代码」 <script setup> window.onload = function () { let height = '想要告诉父窗口的高度' if (window.parent && window.parent.postMessage) { window.parent.postMessage({ height: height }, '*'); } }; </script>「父窗口代码」 <template> <div> <iframe :src="iframeSrc" ref="myRef"></iframe> </div> </template> <script setup> import { onMounted, ref } from 'vue'; const iframeSrc = 'https:******.com'; const myRef = ref(null); onMounted(() => { window.addEventListener('message', iframeMessage); }); const iframeMessage = (event) => { // 验证消息来源,确保安全性 if (event.origin !== 'https:******.com') return; const newHeight = event.data.height; if (newHeight && myRef.value) { myRef.value.style.height = `${newHeight}px`; } }; </script>「注意:」 if (event.origin !== 'https:******.com') return 这行代码记得加上。 iframe嵌入页面免登录处理 这个小弟有单独写过相关详细文章,并且分析了几种情况的处理方式,移步:iframe嵌入页面实现免登录 http无法嵌入https 「简述:」 例如开发环境是HTTP,嵌入的环境是生产环境的HTTPS,这时就会发现这个问题了。其实是现代浏览器的安全机制,会认为是跨域不同源而禁止。因为HTTP协议传输的数据未加密的会有安全风险。 「解决思路:」 网上五花八门的方法,但其实真正靠谱的就两种,(1)将 HTTP 转换成 HTTPS (2)使用代理服务。 方法一:将 HTTP 转换成 HTTPS(推荐) 1、获取 SSL 证书并安装 方法不止一种,这里就细说啦。 2、配置服务器(这里以nginx为例) 下面我把核心部分解释放在注释说明,这是简单版本用于说明HTTP转HTTPS,如果真的上生产其实还有不少其它配置。 server { listen 80; // 监听http默认的80端口 return 301 https://$host$request_uri; // 把所有http永久重定向到https server_name ****.com www.****.com; // 指定域名,这里视真实情况而定 } server { listen 443 ssl; // 监听https默认的443端口。 server_name ****.com www.****.com; // 指定域名,这里视真实情况而定 // 指定 SSL 证书文件路径。 ssl_certificate /etc/lets/live/****.com/fullchain.pem; // 指定 SSL 私钥文件路径 ssl_certificate_key /etc/lets/live/****.com/privkey.pem; location / { index index.html index.htm; root /var/w/html; } }方法二:使用代理服务 用 nodejs 搭建个简单的代理服务器(这里是用 nodejs 举例,真实业务场景可能是后端那边搞) 要先安装对应的依赖,例如 npm init -y npm install express http-proxy然后再配置对应的代理服务器,主要核心是下面四个模块 express:作用是构建 Web 应用。 http:作用是处理 HTTP 请求。 https:作用是处理 HTTPS 请求。 httpProxy:作用是创建代理服务器。 const express = require('express'); const fs = require('fs'); const https = require('https'); const http = require('http'); const httpProxy = require('http-proxy'); const app = express(); const proxy = httpProxy.createProxyServer(); const port = 3000; // 读取对应的SSL证书文件 const options = { key: fs.readFileSync('/etc/lets/live/proxy.****.com/privkey.pem'), cert: fs.readFileSync('/etc/lets/live/proxy.****.com/fullchain.pem') }; // 设置路由信息 app.all('/proxy/*', (req, res) => { const targetUrl = `http://${req.params[0]}`; proxy.web(req, res, { target: targetUrl }, (error) => { res.status(500).send('Proxy request failed'); }); }); // 创建HTTPS服务器 const server = https.createServer(options, app); // 启动代理服务器 server.listen(port, () => { console.log(`HTTPS`); });跨域问题 「简述:」 iframe 页面的跨域问题是因为涉及到浏览器的安全策略,即同源策略。同源策略限制了一个网页脚本不能读写不同源页面的 DOM 与 Cookie之类的信息。即如果 iframe 中的内容与包含它的页面不在同一个源上,那么这两个页面之间会受到跨域限制。 「解决思路:」 1、使用 window.postMessage 实现跨域通信 父页面代码: 主要用window.addEventListener监听消息用postMessage发送消息。 「注意」: @load加载完成后再监听和window.removeEventListener取消监听这两个细节。 <template> <div> <iframe :src="iframeSrc" ref="iframeRef" @load="onIframeLoad" style="width: 100%; height: 400px;"></iframe> <button @click="sendMessage">发送消息</button> </div> </template> <script setup> import { ref, onMounted } from 'vue'; onMounted(() => { window.addEventListener('message', handleMessage); // 在组件卸载时移除事件监听器 return () => { window.removeEventListener('message', handleMessage); }; }); const iframeSrc = 'http://***.com'; const iframeRef = ref(null); // 当 iframe 加载完成后,再设置监听器 const onIframeLoad = () => { window.addEventListener('message', handleMessage); }; const sendMessage = () => { const iframe = iframeRef.value; if (iframe.contentWindow) { iframe.contentWindow.postMessage('Hello!', 'http://***.com'); } }; const handleMessage = (event) => { // 确保来自想要的源才处理消息 if (event.origin !== 'http://***.com') return; console.log(event.data); }; </script>子页面代码:和父页面一样,用window.addEventListener监听消息用postMessage发送消息。 <template> <div> <button @click="sendMessage">发送消息到父页面</button> </div> </template> <script setup> import { ref, onMounted } from 'vue'; onMounted(() => { window.addEventListener('message', handleMessage); // 在组件卸载时移除事件监听器 return () => { window.removeEventListener('message', handleMessage); }; }); const sendMessage = () => { const parentWindow = window.parent; if (parentWindow) { parentWindow.postMessage('Hello!', 'http://****.com'); } }; const handleMessage = (event) => { if (event.origin !== 'http://****.com') return; console.log(event.data); }; </script>2、使用 document.domain document.domain用于解决二级域名之间跨域问题的方法,例如:a.tty.com 和 b.tty.com,它们都属于同一个顶级域名 tty.com,这时就适合用document.domain来让这两个页面能够相互访问。用法相当于简单,就是分别设置两个页面的document.domain。 核心代码在第10与19行。 <template> <div> <iframe :src="iframeSrc" @load="onIframeLoad" ref="iframeRef"></iframe> </div> </template> <script setup> import { ref } from 'vue'; document.domain = 'tty.com'; // 设置顶级域名 const iframeRef = ref(null); const iframeSrc = 'http://b.tty.com'; const onIframeLoad = () => { const iframe = iframeRef.value; if (iframe.contentWindow) { // 设置iframe的 document.domain iframe.contentWindow.document.domain = 'tty.com'; } }; </script>3、使用 CORS 这里主要是后端的配置了,通过调整服务器响应头中的 Access-Control-Allow-Origin 来控制哪些源是可以安全访问资源。 以为nginx为例,*设置为所有。 http { server { listen 80; server_name yourdomain.com; # 替换为你的域名 # 代理 iframe 请求并添加 CORS 头部 location /iframe-proxy/ { # 添加CORS头部 add_header Access-Control-Allow-Origin *; # 其他配置... } } }4、nginx配置代理 算是常见解决方案了,思路是通过 Nginx 反向代理,将请求重定向到想要请求的目标服务器。 核心就是第10行代码,具体可以特意去看看nginx。 http { server { listen 80; server_name yourdomain.com; # 替换为你的域名 # 代理 iframe 请求并添加 CORS 头部 location /iframe-proxy/ { # 将请求代理到目标 proxy_pass http://tty.com/; # 其他配置... } } }iframe嵌入后报拒绝连接请求 不知道你用iframe有没有见过这个页面,这通常是目标页面设置了 X-Frame-Options 响应头来限制内容被嵌入到其他站点的 iframe 中。这个可以找后端看看 X-Frame-Options 。 图片 小结 都是把遇到的场景总结了一下,感觉都是比较常见的情况。 如果大佬们有什么 iframe 的 “坑” 也可以分享一下我同步学习一下,还有那里写的不好也可以指出更正鸭
技术教程
# Web前端
# Vue
易航
1月4日
0
117
0
2025-01-04
掌握 PHP 静态成员:self::, parent::, static:: 详解
图片 在 PHP 中,静态成员(包括方法和属性)直接隶属于类,而非类的实例对象。这意味着我们无需实例化对象,就能直接访问类的静态成员。这一特性在需要跨对象共享数据或功能时尤为有用。 PHP 提供了 self::,parent:: 和 static:: 三个关键字来访问静态成员,它们各自拥有不同的工作机制,尤其是在继承关系中。本文将深入解析这三个关键字的运作原理,并结合实例阐明它们之间的区别。 何时使用静态成员 模拟全局变量: 将静态属性视为类内部的全局变量,所有实例都能共享访问。 提供工具方法: 静态方法适用于提供独立于具体对象实例的实用功能。 定义类常量: 使用静态属性定义类级别常量,确保其值在整个应用生命周期内保持不变。 实现单例模式: 静态方法和属性是实现单例模式(确保一个类只有一个实例)的关键要素。 调用静态方法 要调用静态方法,请使用 :: 运算符,后跟方法名称。 以下是示例: class MyClass { public static function greet() { echo "Hello, world!"; } } MyClass::greet(); // 输出: Hello, world!调用静态属性 要访问静态属性,也可以使用 :: 运算符,后跟属性名称。 以下是示例: class MyClass { public static $count = 0; public static function incrementCount() { self::$count++; } } MyClass::incrementCount(); echo MyClass::$count; // 输出: 1 Use code with caution.三个关键词:self::、、parent::和static 1. self:: self:: 关键字始终指向 代码编写的类 本身,不考虑任何继承关系。这意味着即使子类重写了父类的静态方法或属性,self:: 仍然会引用父类中定义的版本。 2. parent:: parent:: 关键字用于从 直接父类 中调用静态方法或属性。它会绕过子类中任何重写的方法或属性,确保使用的是 父类 的版本。 3. static:: static:: 关键字与 self:: 类似,但它引入了 后期静态绑定 机制。这意味着 static:: 会根据运行时环境动态地绑定到最 派生类 中的静态方法或属性,即使调用代码位于父类中。 举例说明差异 让我们看看这些关键字在具有继承的 PHP 程序中是如何表现的。 示例 1:使用self class A { public static function sayHello() { return "Hello from A"; } public static function test() { return self::sayHello(); } } class B extends A { public static function sayHello() { return "Hello from B"; } } echo B::test(); // 输出: "Hello from A"在这个例子中,self::sayHello() 语句出现在类 A 的代码中,因此 self:: 指向的是类 A 本身。 尽管类 B 重写了 sayHello() 方法,但由于 self:: 的绑定机制,程序仍然会调用 父类 A 中的 sayHello() 方法,最终输出 "Hello from A"。 示例 2:使用parent class A { public static function sayHello() { return "Hello from A"; } } class B extends A { public static function sayHello() { return parent::sayHello() . " and B"; } } echo B::sayHello(); // 输出: "Hello from A and B"在这个例子中,类 B 中的 parent::sayHello() 语句明确指示调用 父类 A 的 sayHello() 方法。因此,程序会先输出父类 A 中的消息,然后拼接上类 B 自身的消息,最终输出 "来自 A 和 B 的问候"。 示例 3:使用static class A { public static function sayHello() { return "Hello from A"; } public static function test() { return static::sayHello(); } } class B extends A { public static function sayHello() { return "Hello from B"; } } echo B::test(); // 输出: "Hello from B"这段代码中,static::sayHello() 语句位于类 A 中,但由于 static:: 支持后期静态绑定,它会指向 运行时确定的最底层派生类,也就是类 B。最终,程序调用的是类 B 中的 sayHello() 方法,输出 "Hello from B"。 主要区别 self::: 引用当前代码所在的类,不考虑继承关系。 当我们希望子类重写方法时,父类中的调用不受影响,就可以使用 self::。 parent::: 专门用于调用父类中的方法或属性,即使子类进行了重写。 当我们需要在子类中扩展父类的功能,但仍然希望保留对父类原始方法的访问权限时,就可以使用 parent::。 static::: 实现后期静态绑定,根据运行时环境动态绑定到最派生类的方法或属性。 当我们希望方法的行为能够根据调用它的类动态调整时,就可以使用 static::。 深入理解 self::,parent:: 和 static:: 之间的区别,有助于我们编写更加健壮、易于维护的面向对象 PHP 代码,尤其是在处理复杂的继承关系时。
技术教程
# PHP
易航
1月4日
0
37
0
2025-01-04
手把手教你在 Vue 项目中优雅地封装 axios!
1.axios 简介 axios 是一个用来发起网络请求的 js 库,返回的格式是 Promise。 vue 项目中基本都是用 axios 发起网络请求。 2.安装配置 axios 2.1 安装 axios npm i axios -- save2.2 配置 axios 创建 Axios 实例 添加请求拦截器 添加响应拦截器 配置全局的 loading 在 src/util 下面新建 axios.js 文件 import axios from "axios"; import { ElMessage } from 'element-plus' import { ElLoading } from 'element-plus' import { ref } from 'vue' // -------------------------1. 创建axios实例----------------------- const instance = axios.create({ // 接口 baseURL: "/api", // 超时时间 timeout: 3000, }); // -------------------------2.请求拦截----------------------- instance.interceptors.request.use( config => { let token = sessionStorage.getItem('token'); if (token) { config.headers['token'] = token } // 加载loading addLoading(); return config; }, error => { // 请求发生错误,抛出异常 Promise.reject(error); } ); // -------------------------3.响应拦截----------------------- instance.interceptors.response.use( res => { // 取消加载 loading cancelLoading(); return res; }, error => { // 取消加载 loading cancelLoading(); if (error && error.response) { const status = error.response.status switch (status) { case 400: ElMessage.error("请求错误"); break; case 401: ElMessage.error("未授权,请重新登录"); break; case 403: ElMessage.error("登录过期,请重新登录"); break; case 404: ElMessage.error("请求错误,未找到相应的资源"); break; case 408: ElMessage.error("请求超时"); break; case 500: ElMessage.error("服务器错误"); break; case 504: ElMessage.error("网络超时"); break; default: ElMessage.error("请求失败"); } } else { if (JSON.stringify(error).includes("timeout")) { error.code = "TIMEOUT"; error.message = "服务器响应超时,请刷新页面"; } } return Promise.reject(error); }, ); // -------------------------4.配置全局loading----------------------- let loadCount = 0; let loadingInstance = ref(null); // 加载loading const addLoading = () => { loadCount++; if (loadCount === 1) { loadingInstance.value = ElLoading.service({ fullscreen: false, text: "正在请求数据中....", background: "rgba(0, 0, 0, 0)", }); } }; // 取消加载loading const cancelLoading = () => { loadCount--; if (loadCount === 0) { loadingInstance.value.close(); }; }; // -------------------------配置全局loading----------------------- // 5.导出 axios 实例 export default instance;2.3 封装常用的 http 请求 在 /src/util 下面新建 http.js 文件 其实就是先引入 axios 实例,然后将 axios 的几种常用网络请求封装成 Promise 并返回。import instance from "./axios"; const post = (url, data) => { return new Promise((resolve, reject) => { instance .post(url, data) .then((res) => { resolve(res); }) .catch((err) => { reject(err); }); }); }; const get = (url, data) => { return new Promise((resolve, reject) => { instance .get(url, { params: data }) .then((res) => { resolve(res); }) .catch((err) => { reject(err); }); }); }; const put = (url, data) => { return new Promise((resolve, reject) => { instance .put(url, data) .then((res) => { resolve(res); }) .catch((err) => { reject(err); }); }); }; const del = (url, data) => { return new Promise((resolve, reject) => { instance .delete(url, { params: data }) .then((res) => { resolve(res); }) .catch((err) => { reject(err); }); }); }; export default { post, get, put, del, };2.4 开发接口 在 /src/api 文件夹下新建接口文件 import http from "../utils/http"; // 用户登录 const login = (data) => { return http.post("/index/user/login", data); }; export default { login }图片 3.请求案例 // 导入用户api import userApi from "../api/user"; // 登录 const onSubmit = async () => { const res = await userApi.login(form); if (res.data.code == 200) { // 登录逻辑 } else { ElMessage.error(res.data.message); } };图片
技术教程
# Web前端
# Vue
易航
1月4日
0
103
0
2024-12-28
Web前端与众不同的夜间开关交互效果(附源码)
图片 这是一个精美炫酷的日/夜开关切换按钮效果。这个效果展示了如何通过纯CSS和少量JavaScript来创建复杂、富有动感的用户界面元素。它不仅功能性强,还具有很高的视觉吸引力,为用户提供了愉悦的交互体验。 主要特点和核心实现原理如下: 视觉效果: 一个圆形的切换按钮,模拟了日夜交替的场景。 日间模式显示太阳、云朵和一个小飞机。 夜间模式显示月亮、星星和一个宇航员熊。 切换时有平滑的动画过渡效果。 核心实现原理: a. HTML结构: b. CSS技术: c. JavaScript: 根据复选框状态同步更新body的data-dark-mode属性。 使用CSS变量(如 --dark)控制日/夜模式的状态。 大量使用CSS transitions和animations实现平滑的动画效果。 使用transform属性(如translate、scale、rotate)实现元素的移动和变形。 使用clip-path和overflow控制元素的可见区域。 巧妙运用z-index和定位来管理层叠关系。 使用SVG创建复杂的图形元素(如云、星星、熊等)。 使用嵌套的span元素组织不同的视觉元素。 关键技巧: 使用CSS变量和calc()函数动态计算样式值,实现平滑过渡。 利用SVG的灵活性创建复杂的图形和动画。 通过改变单一CSS变量(--dark)来控制整个场景的变化。 创作来源:Jhey - Night && Day Toggle ☀️/🌙 详细代码解析:与众不同的夜间开关交互效果源代码 可上下滑动查看完整源代码: <!DOCTYPE html> <html lang="en"> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> <style> *, *:after, *:before { box-sizing: border-box; } :root { --slide-ease: cubic-bezier(.4, -0.3, .6, 1.3); --easing: var(--slide-ease); --speed: 0.5s; --width: clamp(200px, 45vmin, 500px); --ar: 8 / 3; --ray: hsl(0 0% 100% / 0.5); --sun: hsl(47, 91%, 58%); --moon: hsl(212, 13%, 82%); --crater: hsl(221, 16%, 68%); --bg: hsl(219, 30%, 88%); --bear-speed: 10s; --color: hsl(219 30% 20%); } [data-dark-mode=true] { --bg: hsl(219, 30%, 12%); --color: hsl(219 30% 98%); } body { display: grid; place-items: center; min-height: 100vh; overflow: hidden; background: var(--bg); transition: background var(--speed) var(--easing); font-family: sans-serif, system-ui; } .toggle__backdrop:first-of-type .clouds path:first-of-type { fill: var(--ray); } .toggle { -webkit-tap-highlight-color: transparent; width: var(--width); /* random attempts at tackling the overflow iOS issue */ z-index: 10; will-change: transform; isolation: isolate; transform: translate3d(0, 0, 0); /* End of workaround city */ aspect-ratio: var(--ar); border-radius: 100vh; border: 0; position: relative; padding: 0; overflow: hidden; cursor: pointer; transition: background var(--speed) var(--easing); --sky: hsl(204, 53%, 47%); --night: hsl(229, 25%, 16%); outline-color: transparent; background: hsl(calc(204 + (var(--dark, 0) * 25)) calc((53 - (var(--dark, 0) * 28)) * 1%) calc((47 - (var(--dark, 0) * 31)) * 1%)); box-shadow: calc(var(--width) * 0) calc(var(--width) * 0.02) calc(var(--width) * 0.01) calc(var(--width) * -0.0025) hsl(210 10% 100% / 0.95), calc(var(--width) * 0) calc(var(--width) * -0.02) calc(var(--width) * 0.01) calc(var(--width) * -0.0025) hsl(210 10% 10% / 0.2), calc(var(--width) * 0) calc(var(--width) * 0.02) calc(var(--width) * 0.5) 0 hsl(210 10% 100% / 0.15); } .toggle:after { content: ""; position: absolute; inset: 0; box-shadow: calc(var(--width) * 0) calc(var(--width) * -0.025) calc(var(--width) * 0.025) 0 hsl(210 10% 10% / 0.15) inset, calc(var(--width) * 0) calc(var(--width) * 0.025) calc(var(--width) * 0.025) 0 hsl(210 10% 10% / 0.65) inset; border-radius: 100vh; } .toggle__content { position: absolute; top: 0; left: 0; right: 0; bottom: 0; overflow: hidden; border-radius: 100vh; display: block; clip-path: inset(0 0 0 0 round 100vh); } .toggle__backdrop { overflow: visible !important; position: absolute; bottom: 0; width: 100%; left: 0; transition: translate var(--speed) var(--easing); translate: 0 calc(var(--dark, 0) * (100% - (3 / 8 * var(--width)))); } [aria-pressed=false] .toggle__backdrop:last-of-type { transition-timing-function: cubic-bezier(.2, -0.6, .7, 1.6); } [aria-pressed=false] .stars path { transition-delay: 0s; } .stars path { transform-box: fill-box; transform-origin: 25% 50%; scale: calc(0.25 + (var(--dark, 0) * 0.75)); transition: scale var(--speed) calc(var(--speed) * 0.5) var(--easing); } .toggle__indicator { height: 100%; aspect-ratio: 1; border-radius: 0%; display: grid; place-items: center; padding: 3%; } .pilot-bear { position: absolute; width: 25%; } .toggle__star { height: 100%; aspect-ratio: 1; border-radius: 50%; position: relative; transition: translate var(--speed) var(--easing); translate: calc((var(--dark, 0) * -10%) + 5%) 0; /* translate: calc((var(--dark, 0) * -18%) + 5%) 0; */ } .sun { background: var(--sun); position: absolute; inset: 0; border-radius: 50%; overflow: hidden; box-shadow: calc(var(--width) * 0.01) calc(var(--width) * 0.01) calc(var(--width) * 0.02) 0 hsl(210 10% 100% / 0.95) inset, calc(var(--width) * -0.01) calc(var(--width) * -0.01) calc(var(--width) * 0.02) 0 hsl(210 10% 20% / 0.5) inset; } .moon { position: absolute; inset: -1%; border-radius: 50%; background: var(--moon); transition: translate var(--speed) ease-in-out; translate: calc((100 - (var(--dark, 0) * 100)) * 1%) 0%; box-shadow: calc(var(--width) * 0.01) calc(var(--width) * 0.01) calc(var(--width) * 0.02) 0 hsl(210 10% 100% / 0.95) inset, calc(var(--width) * -0.01) calc(var(--width) * -0.01) calc(var(--width) * 0.02) 0 hsl(210 10% 10% / 0.95) inset; } .moon__crater { position: absolute; background: var(--crater); border-radius: 50%; width: calc(var(--size, 10) * 1%); aspect-ratio: 1; left: calc(var(--x) * 1%); top: calc(var(--y) * 1%); box-shadow: calc(var(--width) * 0.01) calc(var(--width) * 0.01) calc(var(--width) * 0.01) 0 hsl(210 10% 6% / 0.25) inset, 0 calc(var(--width) * 0.005) calc(var(--width) * 0.01) 0 hsl(210 10% 100% / 0.25); } .moon__crater:nth-of-type(1) { --size: 18; --x: 40; --y: 15; } .moon__crater:nth-of-type(2) { --size: 20; --x: 65; --y: 58; } .moon__crater:nth-of-type(3) { --size: 34; --x: 18; --y: 40; } .toggle__star:before { content: ""; z-index: -1; width: 356%; background: radial-gradient(hsl(0 0% 100% / 0.25) 40%, transparent 40.5%), radial-gradient(hsl(0 0% 100% / 0.25) 56%, transparent 56.5%) hsl(0 0% 100% / 0.25); border-radius: 50%; aspect-ratio: 1; position: absolute; top: 50%; left: 50%; transition: translate var(--speed) var(--easing); translate: calc((50 - (var(--dark, 0) * 4)) * -1%) -50%; } .toggle__star:after { content: ""; position: absolute; inset: 0; display: block; background: hsl(0 0% 0% / 0.5); filter: blur(4px); translate: 2% 4%; border-radius: 50%; z-index: -1; } .toggle__indicator-wrapper { position: absolute; inset: 0; transition: translate var(--speed) var(--slide-ease); translate: calc(var(--dark, 0) * (var(--width) - (3 / 8 * var(--width)))) 0; } [aria-pressed=true] { --dark: 1; } /* Fun stuff! */ /* We have 11 stars */ .stars g { transform-box: fill-box; transform-origin: 50% 50%; } .stars g:nth-of-type(3) { animation: twinkle 4s -2s infinite; } .stars g:nth-of-type(11) { animation: twinkle 6s -2s infinite; } .stars g:nth-of-type(9) { animation: twinkle 4s -1s infinite; } @keyframes twinkle { 0%, 40%, 60%, 100% { transform: scale(1); } 50% { transform: scale(0); } } .astrobear { width: 12%; position: absolute; top: 100%; left: 0%; transition: translate calc(var(--speed) + (var(--dark, 0) * (var(--bear-speed) - var(--speed)))) calc(var(--bear-speed) * (0.4 * var(--dark, 0))) linear; translate: calc(var(--dark, 0) * 400%) calc(var(--dark, 0) * -350%); } .astrobear svg { transform-origin: 50% 75%; scale: var(--dark, 0); rotate: calc(var(--dark, 0) * 360deg); transition: rotate calc(var(--speed) + (var(--dark, 0) * (var(--bear-speed) - var(--speed)))) calc(var(--bear-speed) * 0.4) linear, scale var(--speed) ease-in-out; } .astrobear__container { position: absolute; overflow: hidden; inset: 0; clip-path: inset(0 0 0 0); opacity: var(--dark, 0); translate: 0 calc(-200% + (var(--dark, 0) * 200%)); transition: opacity var(--speed) var(--easing), translate var(--speed) var(--easing); } .pilot__container { position: absolute; overflow: hidden; inset: 0; clip-path: inset(0 0 0 0); opacity: calc(1 - var(--dark, 0)); translate: 0 calc(var(--dark, 0) * 200%); transition: opacity var(--speed) var(--easing), translate var(--speed) var(--easing); } .pilot-bear { width: 18%; position: absolute; top: 70%; left: 100%; transition: translate calc(var(--speed) + ((1 - var(--dark, 0)) * ((var(--bear-speed) * 0.5) - var(--speed)))) calc((var(--bear-speed) * 0.5) * ((1 - var(--dark, 0)) * 0.4)) linear; translate: calc((0 - (1 - var(--dark, 0))) * (var(--width) + 100%)) calc((0 - (1 - var(--dark, 0))) * (200%)); } .pilot { rotate: 12deg; animation: fly 4s infinite ease-in-out; width: 100%; } @keyframes fly { 50% { translate: 0 -25%; } } .controls { position: fixed; bottom: 1rem; right: 1rem; display: flex; align-items: center; gap: 0.5rem; font-family: sans-serif; color: var(--color); transition: color var(--speed) var(--easing); } [type=checkbox] { accent-color: var(--color); transition: accent-color var(--speed) var(--easing); } </style> </head> <body> <div class="controls"> <label for="sync">Sync <body></label> <input id="sync" type="checkbox" /> </div> <!-- 背景色控制 --> <button class="toggle" aria-pressed="false" title="Toggle Dark Mode"> <span class="toggle__content"> <!-- light模式的云2 --> <svg aria-hidden=true class="toggle__backdrop" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 290 228"> <g class="clouds"> <path fill="#D9D9D9" d="M335 147.5c0 27.89-22.61 50.5-50.5 50.5a50.78 50.78 0 0 1-9.29-.853c-2.478 12.606-10.595 23.188-21.615 29.011C245.699 243.749 228.03 256 207.5 256a50.433 50.433 0 0 1-16.034-2.599A41.811 41.811 0 0 1 166 262a41.798 41.798 0 0 1-22.893-6.782A42.21 42.21 0 0 1 135 256a41.82 41.82 0 0 1-19.115-4.592A41.84 41.84 0 0 1 88 262c-1.827 0-3.626-.117-5.391-.343C74.911 270.448 63.604 276 51 276c-23.196 0-42-18.804-42-42s18.804-42 42-42c1.827 0 3.626.117 5.391.343C64.089 183.552 75.396 178 88 178a41.819 41.819 0 0 1 19.115 4.592C114.532 176.002 124.298 172 135 172a41.798 41.798 0 0 1 22.893 6.782 42.066 42.066 0 0 1 7.239-.773C174.137 164.159 189.749 155 207.5 155c.601 0 1.199.01 1.794.031A41.813 41.813 0 0 1 234 147h.002c.269-27.66 22.774-50 50.498-50 27.89 0 50.5 22.61 50.5 50.5Z" /> </g> </svg> <!-- light模式的小飞机 --> <span aria-hidden=true class="pilot__container"> <span class="pilot-bear"> <img src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/f13edbe752dd4d11b7c394aaf0f68637~tplv-k3u1fbpfcp-watermark.image?" alt="pilot-bear" class="pilot" /> </span> </span> <!-- light模式的云1 --> <svg aria-hidden=true class="toggle__backdrop" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 290 228"> <g class="clouds"> <path fill="#fff" d="M328 167.5c0 15.214-7.994 28.56-20.01 36.068.007.31.01.621.01.932 0 23.472-19.028 42.5-42.5 42.5-3.789 0-7.461-.496-10.957-1.426C249.671 263.676 233.141 277 213.5 277a42.77 42.77 0 0 1-7.702-.696C198.089 284.141 187.362 289 175.5 289a42.338 42.338 0 0 1-27.864-10.408A42.411 42.411 0 0 1 133.5 281c-4.36 0-8.566-.656-12.526-1.876C113.252 287.066 102.452 292 90.5 292a42.388 42.388 0 0 1-15.8-3.034A42.316 42.316 0 0 1 48.5 298C25.028 298 6 278.972 6 255.5S25.028 213 48.5 213a42.388 42.388 0 0 1 15.8 3.034A42.316 42.316 0 0 1 90.5 207c4.36 0 8.566.656 12.526 1.876C110.748 200.934 121.548 196 133.5 196a42.338 42.338 0 0 1 27.864 10.408A42.411 42.411 0 0 1 175.5 204c2.63 0 5.204.239 7.702.696C190.911 196.859 201.638 192 213.5 192c3.789 0 7.461.496 10.957 1.426 2.824-10.491 9.562-19.377 18.553-24.994-.007-.31-.01-.621-.01-.932 0-23.472 19.028-42.5 42.5-42.5s42.5 19.028 42.5 42.5Z" /> </g> </svg> <span class="toggle__indicator-wrapper"> <span class="toggle__indicator"> <span class="toggle__star"> <span class="sun"> <span class="moon"> <span class="moon__crater"></span> <span class="moon__crater"></span> <span class="moon__crater"></span> </span> </span> </span> </span> </span> <!-- dark模式的星星 --> <svg aria-hidden=true class="toggle__backdrop" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 290 228"> <g> <g class="stars"> <g> <path fill="#fff" fill-rule="evenodd" d="M61 11.5a.75.75 0 0 1 .721.544l.813 2.846a3.75 3.75 0 0 0 2.576 2.576l2.846.813a.75.75 0 0 1 0 1.442l-2.846.813a3.749 3.749 0 0 0-2.576 2.576l-.813 2.846a.75.75 0 0 1-1.442 0l-.813-2.846a3.749 3.749 0 0 0-2.576-2.576l-2.846-.813a.75.75 0 0 1 0-1.442l2.846-.813a3.749 3.749 0 0 0 2.576-2.576l.813-2.846A.75.75 0 0 1 61 11.5Z" clip-rule="evenodd" /> </g> <g> <path fill="#fff" fill-rule="evenodd" d="M62.5 45.219a.329.329 0 0 1 .315.238l.356 1.245a1.641 1.641 0 0 0 1.127 1.127l1.245.356a.328.328 0 0 1 0 .63l-1.245.356a1.641 1.641 0 0 0-1.127 1.127l-.356 1.245a.328.328 0 0 1-.63 0l-.356-1.245a1.641 1.641 0 0 0-1.127-1.127l-1.245-.356a.328.328 0 0 1 0-.63l1.245-.356a1.641 1.641 0 0 0 1.127-1.127l.356-1.245a.328.328 0 0 1 .315-.238Z" clip-rule="evenodd" /> </g> <g> <path fill="#fff" fill-rule="evenodd" d="M32 31.188a.28.28 0 0 1 .27.204l.305 1.067a1.405 1.405 0 0 0 .966.966l1.068.305a.28.28 0 0 1 0 .54l-1.068.305a1.405 1.405 0 0 0-.966.966l-.305 1.068a.28.28 0 0 1-.54 0l-.305-1.068a1.406 1.406 0 0 0-.966-.966l-1.067-.305a.28.28 0 0 1 0-.54l1.067-.305a1.406 1.406 0 0 0 .966-.966l.305-1.068a.281.281 0 0 1 .27-.203Z" clip-rule="evenodd" /> </g> <g> <path fill="#fff" fill-rule="evenodd" d="M41.5 74.219a.329.329 0 0 1 .315.238l.356 1.245a1.641 1.641 0 0 0 1.127 1.127l1.245.356a.328.328 0 0 1 0 .63l-1.245.356a1.641 1.641 0 0 0-1.127 1.127l-.356 1.245a.328.328 0 0 1-.63 0l-.356-1.245a1.641 1.641 0 0 0-1.127-1.127l-1.245-.356a.328.328 0 0 1 0-.63l1.245-.356a1.641 1.641 0 0 0 1.127-1.127l.356-1.245a.328.328 0 0 1 .315-.238Z" clip-rule="evenodd" /> </g> <g> <path fill="#fff" fill-rule="evenodd" d="M34 83.188a.28.28 0 0 1 .27.203l.305 1.068a1.405 1.405 0 0 0 .966.966l1.068.305a.28.28 0 0 1 0 .54l-1.068.305a1.405 1.405 0 0 0-.966.966l-.305 1.068a.28.28 0 0 1-.54 0l-.305-1.068a1.406 1.406 0 0 0-.966-.966l-1.068-.305a.28.28 0 0 1 0-.54l1.068-.305a1.406 1.406 0 0 0 .966-.966l.305-1.068a.281.281 0 0 1 .27-.204Z" clip-rule="evenodd" /> </g> <g> <path fill="#fff" fill-rule="evenodd" d="M63 89.25a.375.375 0 0 1 .36.272l.407 1.423a1.874 1.874 0 0 0 1.288 1.288l1.423.406a.374.374 0 0 1 0 .722l-1.423.406a1.874 1.874 0 0 0-1.288 1.288l-.407 1.423a.374.374 0 0 1-.72 0l-.407-1.423a1.874 1.874 0 0 0-1.288-1.288l-1.423-.406a.374.374 0 0 1 0-.722l1.423-.406a1.874 1.874 0 0 0 1.288-1.288l.407-1.423a.376.376 0 0 1 .36-.272Z" clip-rule="evenodd" /> </g> <g> <path fill="#fff" fill-rule="evenodd" d="M110.5 53.156a.236.236 0 0 1 .225.17l.254.89a1.174 1.174 0 0 0 .805.805l.89.254a.23.23 0 0 1 .122.084.233.233 0 0 1-.122.366l-.89.254a1.167 1.167 0 0 0-.805.805l-.254.89a.232.232 0 0 1-.225.17.235.235 0 0 1-.225-.17l-.254-.89a1.174 1.174 0 0 0-.805-.805l-.89-.254a.23.23 0 0 1-.122-.084.233.233 0 0 1 .122-.366l.89-.254a1.167 1.167 0 0 0 .805-.805l.254-.89a.232.232 0 0 1 .225-.17Z" clip-rule="evenodd" /> </g> <g> <path fill="#fff" fill-rule="evenodd" d="M120 27.188a.279.279 0 0 1 .27.204l.305 1.067a1.41 1.41 0 0 0 .966.966l1.067.305a.283.283 0 0 1 .148.1.286.286 0 0 1 0 .34.283.283 0 0 1-.148.1l-1.067.305a1.403 1.403 0 0 0-.966.966l-.305 1.067a.279.279 0 0 1-.439.147.275.275 0 0 1-.101-.147l-.305-1.067a1.41 1.41 0 0 0-.966-.966l-1.068-.305a.284.284 0 0 1-.147-.1.286.286 0 0 1 0-.34.284.284 0 0 1 .147-.1l1.068-.305a1.405 1.405 0 0 0 .966-.966l.305-1.067a.279.279 0 0 1 .27-.204Z" clip-rule="evenodd" /> </g> <g> <path fill="#fff" fill-rule="evenodd" d="M155 28.5a.753.753 0 0 1 .721.544l.813 2.846a3.746 3.746 0 0 0 2.576 2.576l2.846.813a.747.747 0 0 1 .543.721.75.75 0 0 1-.543.721l-2.846.813a3.75 3.75 0 0 0-2.576 2.576l-.813 2.846a.747.747 0 0 1-.721.543.749.749 0 0 1-.721-.543l-.813-2.846a3.746 3.746 0 0 0-2.576-2.576l-2.846-.813a.747.747 0 0 1-.543-.721.75.75 0 0 1 .543-.721l2.846-.813a3.75 3.75 0 0 0 2.576-2.576l.813-2.846A.751.751 0 0 1 155 28.5Z" clip-rule="evenodd" /> </g> <g> <path fill="#fff" fill-rule="evenodd" d="M147 60.25a.377.377 0 0 1 .36.272l.407 1.423a1.883 1.883 0 0 0 1.288 1.288l1.423.407a.375.375 0 0 1 0 .72l-1.423.407a1.875 1.875 0 0 0-1.288 1.288l-.407 1.423a.371.371 0 0 1-.36.272.377.377 0 0 1-.36-.272l-.407-1.423a1.883 1.883 0 0 0-1.288-1.288l-1.423-.406a.375.375 0 0 1 0-.722l1.423-.406a1.875 1.875 0 0 0 1.288-1.288l.407-1.423a.372.372 0 0 1 .36-.272Z" clip-rule="evenodd" /> </g> <g> <path fill="#fff" fill-rule="evenodd" d="M125.5 76.344a.513.513 0 0 1 .496.374l.559 1.956a2.574 2.574 0 0 0 1.771 1.771l1.956.56a.514.514 0 0 1 .27.805.514.514 0 0 1-.27.186l-1.956.559a2.57 2.57 0 0 0-1.771 1.77l-.559 1.957a.514.514 0 0 1-.806.27.514.514 0 0 1-.186-.27l-.559-1.956a2.574 2.574 0 0 0-1.771-1.771l-1.956-.56a.514.514 0 0 1-.27-.805.514.514 0 0 1 .27-.186l1.956-.559a2.57 2.57 0 0 0 1.771-1.77l.559-1.957a.515.515 0 0 1 .496-.374Z" clip-rule="evenodd" /> </g> </g> </g> </svg> <!-- 太空熊动画 --> <span class="astrobear__container"> <span class="astrobear"> <svg aria-hidden=true xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 316 432"> <circle cx="158" cy="143" r="140" fill="#444" /> <circle cx="158" cy="143" r="140" fill="url(#a)" fill-opacity=".2" /> <circle cx="158" cy="143" r="140" stroke="#000" stroke-width="6" /> <path fill="#AF7128" fill-rule="evenodd" d="M65.98 159.61C49.913 155.643 38 141.134 38 123.842 38 103.495 54.495 87 74.842 87c14.337 0 26.761 8.19 32.85 20.146C119.687 100.674 133.414 97 148 97h20c14.52 0 28.19 3.641 40.146 10.059C214.251 95.15 226.65 87 240.952 87c20.347 0 36.842 16.495 36.842 36.842 0 17.222-11.818 31.685-27.787 35.72A85.104 85.104 0 0 1 253 182v66.56l10.054-10.054c11.325-11.325 29.687-11.325 41.012 0s11.325 29.687 0 41.012l-44.548 44.548a29.004 29.004 0 0 1-6.518 4.906V407c0 12.15-9.85 22-22 22h-44c-12.15 0-22-9.85-22-22v-28.69a41.072 41.072 0 0 1-14 .174V407c0 12.15-9.85 22-22 22H85c-12.15 0-22-9.85-22-22v-77.797a28.99 28.99 0 0 1-6.946-5.137l-44.548-44.548c-11.325-11.325-11.325-29.687 0-41.012 11.326-11.325 29.687-11.325 41.013 0L63 248.988V182a85.106 85.106 0 0 1 2.98-22.39Z" clip-rule="evenodd" /> <path fill="#000" d="m65.98 159.61 2.894.789a3.002 3.002 0 0 0-2.175-3.701l-.72 2.912Zm41.712-52.464-2.673 1.362a3 3 0 0 0 4.098 1.279l-1.425-2.641Zm100.454-.087-1.419 2.643a3 3 0 0 0 4.089-1.274l-2.67-1.369Zm41.861 52.503-.735-2.908a2.997 2.997 0 0 0-2.159 3.698l2.894-.79ZM253 248.56h-3a3 3 0 0 0 5.121 2.121L253 248.56Zm10.054-10.054-2.121-2.121 2.121 2.121Zm41.012 0-2.121 2.122 2.121-2.122Zm0 41.012 2.121 2.122-2.121-2.122ZM253 328.972l-1.448-2.627a3 3 0 0 0-1.552 2.627h3Zm-88 49.338h3a3 3 0 0 0-3.548-2.949l.548 2.949Zm-14 .174.475-2.963a3 3 0 0 0-3.475 2.963h3Zm-88-49.281h3a3 3 0 0 0-1.597-2.651L63 329.203Zm-6.946-5.137-2.121 2.121 2.121-2.121Zm-44.548-44.548-2.121 2.122 2.121-2.122Zm0-41.012 2.122 2.122-2.122-2.122Zm41.013 0-2.122 2.122 2.122-2.122ZM63 248.988l-2.121 2.121A2.999 2.999 0 0 0 66 248.988h-3ZM35 123.842c0 18.704 12.886 34.391 30.26 38.681l1.439-5.825C51.941 153.054 41 139.721 41 123.842h-6ZM74.842 84C52.838 84 35 101.838 35 123.842h6C41 105.151 56.151 90 74.842 90v-6Zm35.524 21.785C103.785 92.862 90.351 84 74.842 84v6c13.165 0 24.58 7.517 30.177 18.508l5.347-2.723ZM148 94c-15.095 0-29.311 3.803-41.733 10.506l2.85 5.281C120.685 103.544 133.924 100 148 100v-6Zm20 0h-20v6h20v-6Zm41.565 10.416C197.183 97.769 183.027 94 168 94v6c14.013 0 27.196 3.512 38.727 9.702l2.838-5.286ZM240.952 84c-15.471 0-28.878 8.82-35.476 21.691l5.34 2.737C216.427 97.481 227.819 90 240.952 90v-6Zm39.842 39.842c0-22.004-17.838-39.842-39.842-39.842v6c18.69 0 33.842 15.151 33.842 33.842h6Zm-30.052 38.629c17.269-4.364 30.052-20 30.052-38.629h-6c0 15.816-10.853 29.104-25.522 32.812l1.47 5.817ZM256 182a88.09 88.09 0 0 0-3.099-23.228l-5.788 1.58A82.082 82.082 0 0 1 250 182h6Zm0 66.56V182h-6v66.56h6Zm-.879 2.121 10.054-10.053-4.242-4.243-10.054 10.054 4.242 4.242Zm10.054-10.053c10.154-10.154 26.616-10.154 36.77 0l4.242-4.243c-12.496-12.497-32.758-12.497-45.254 0l4.242 4.243Zm36.77 0c10.153 10.153 10.153 26.615 0 36.769l4.242 4.243c12.497-12.497 12.497-32.758 0-45.255l-4.242 4.243Zm0 36.769-44.548 44.548 4.243 4.242 44.547-44.547-4.242-4.243Zm-44.548 44.548a26.013 26.013 0 0 1-5.845 4.4l2.896 5.255a32.006 32.006 0 0 0 7.192-5.413l-4.243-4.242ZM256 360v-31.028h-6V360h6Zm0 47v-47h-6v47h6Zm-25 25c13.807 0 25-11.193 25-25h-6c0 10.493-8.506 19-19 19v6Zm-44 0h44v-6h-44v6Zm-25-25c0 13.807 11.193 25 25 25v-6c-10.493 0-19-8.507-19-19h-6Zm0-28.69V407h6v-28.69h-6Zm-4.5 3.69c2.74 0 5.429-.253 8.048-.74l-1.096-5.899c-2.261.42-4.583.639-6.952.639v6Zm-6.975-.554c2.279.365 4.608.554 6.975.554v-6c-2.047 0-4.058-.163-6.025-.479l-.95 5.925ZM154 407v-28.516h-6V407h6Zm-25 25c13.807 0 25-11.193 25-25h-6c0 10.493-8.506 19-19 19v6Zm-44 0h44v-6H85v6Zm-25-25c0 13.807 11.193 25 25 25v-6c-10.493 0-19-8.507-19-19h-6Zm0-47v47h6v-47h-6Zm0-30.797V360h6v-30.797h-6Zm-6.067-3.016a32.008 32.008 0 0 0 7.664 5.668l2.806-5.303a26.002 26.002 0 0 1-6.228-4.607l-4.242 4.242ZM9.385 281.64l44.548 44.547 4.242-4.242-44.547-44.548-4.243 4.243Zm0-45.255c-12.497 12.497-12.497 32.758 0 45.255l4.243-4.243c-10.154-10.154-10.154-26.616 0-36.769l-4.243-4.243Zm45.255 0c-12.497-12.497-32.758-12.497-45.255 0l4.243 4.243c10.153-10.154 26.616-10.154 36.77 0l4.242-4.243Zm10.481 10.481L54.64 236.385l-4.243 4.243 10.482 10.481 4.242-4.243ZM60.001 182v66.988h6V182h-6Zm3.084-23.178A88.1 88.1 0 0 0 60 182h6c0-7.48 1.001-14.722 2.874-21.601l-5.789-1.577Z" /> <path fill="#fff" fill-rule="evenodd" d="M267.721 234.712C241.49 266.061 202.073 286 158 286c-43.749 0-82.91-19.647-109.141-50.598-11.328-8.104-27.18-7.069-37.353 3.104-11.325 11.325-11.325 29.687 0 41.012l44.548 44.548A28.99 28.99 0 0 0 63 329.203V407c0 12.15 9.85 22 22 22h44c12.15 0 22-9.85 22-22v-28.517c2.123.341 4.293.517 6.5.517 2.555 0 5.06-.236 7.5-.69V407c0 12.15 9.85 22 22 22h44c12.15 0 22-9.85 22-22V328.972a29.004 29.004 0 0 0 6.518-4.906l44.548-44.548c11.325-11.325 11.325-29.687 0-41.012-9.875-9.875-25.099-11.139-36.345-3.794Z" clip-rule="evenodd" /> <path fill="url(#b)" fill-opacity=".5" fill-rule="evenodd" d="M267.721 234.712C241.49 266.061 202.073 286 158 286c-43.749 0-82.91-19.647-109.141-50.598-11.328-8.104-27.18-7.069-37.353 3.104-11.325 11.325-11.325 29.687 0 41.012l44.548 44.548A28.99 28.99 0 0 0 63 329.203V407c0 12.15 9.85 22 22 22h44c12.15 0 22-9.85 22-22v-28.517c2.123.341 4.293.517 6.5.517 2.555 0 5.06-.236 7.5-.69V407c0 12.15 9.85 22 22 22h44c12.15 0 22-9.85 22-22V328.972a29.004 29.004 0 0 0 6.518-4.906l44.548-44.548c11.325-11.325 11.325-29.687 0-41.012-9.875-9.875-25.099-11.139-36.345-3.794Z" clip-rule="evenodd" /> <path fill="#000" d="m267.721 234.712-1.64-2.511c-.248.162-.47.359-.66.586l2.3 1.925Zm-218.862.69 2.289-1.94a3.026 3.026 0 0 0-.544-.5l-1.745 2.44Zm-37.353 3.104 2.122 2.121-2.122-2.121Zm0 41.012-2.121 2.122 2.121-2.122Zm44.548 44.548-2.121 2.121 2.121-2.121ZM63 329.203h3a2.999 2.999 0 0 0-1.597-2.651L63 329.203Zm88 49.28.475-2.962a3 3 0 0 0-3.475 2.962h3Zm14-.173h3a3 3 0 0 0-3.548-2.949l.548 2.949Zm88-49.338-1.448-2.627a3 3 0 0 0-1.552 2.627h3Zm51.066-49.454 2.121 2.122-2.121-2.122Zm0-41.012-2.121 2.121 2.121-2.121Zm-38.645-5.719C239.735 263.484 201.148 283 158 283v6c44.999 0 85.245-20.361 112.022-52.362l-4.601-3.851ZM158 283c-42.831 0-81.167-19.23-106.852-49.538l-4.578 3.879C73.347 268.937 113.332 289 158 289v-6ZM13.628 240.627c9.118-9.118 23.331-10.049 33.486-2.785l3.49-4.88c-12.502-8.944-29.991-7.805-41.219 3.423l4.243 4.242Zm0 36.77c-10.154-10.154-10.154-26.616 0-36.77l-4.243-4.242c-12.497 12.497-12.497 32.758 0 45.255l4.243-4.243Zm44.547 44.548-44.547-44.548-4.243 4.243 44.548 44.547 4.242-4.242Zm6.228 4.607a26.002 26.002 0 0 1-6.228-4.607l-4.242 4.242a32.008 32.008 0 0 0 7.664 5.668l2.806-5.303ZM66 360v-30.797h-6V360h6Zm0 47v-47h-6v47h6Zm19 19c-10.493 0-19-8.507-19-19h-6c0 13.807 11.193 25 25 25v-6Zm44 0H85v6h44v-6Zm19-19c0 10.493-8.506 19-19 19v6c13.807 0 25-11.193 25-25h-6Zm0-28.517V407h6v-28.517h-6Zm9.5-2.483c-2.047 0-4.058-.163-6.025-.479l-.95 5.925c2.279.365 4.608.554 6.975.554v-6Zm6.952-.639c-2.261.42-4.583.639-6.952.639v6c2.74 0 5.429-.253 8.048-.74l-1.096-5.899ZM168 407v-28.69h-6V407h6Zm19 19c-10.493 0-19-8.507-19-19h-6c0 13.807 11.193 25 25 25v-6Zm44 0h-44v6h44v-6Zm19-19c0 10.493-8.506 19-19 19v6c13.807 0 25-11.193 25-25h-6Zm0-47v47h6v-47h-6Zm0-31.028V360h6v-31.028h-6Zm7.397-7.027a26.043 26.043 0 0 1-5.845 4.4l2.896 5.255a32.036 32.036 0 0 0 7.192-5.413l-4.243-4.242Zm44.548-44.548-44.548 44.548 4.243 4.242 44.547-44.547-4.242-4.243Zm0-36.77c10.153 10.154 10.153 26.616 0 36.77l4.242 4.243c12.497-12.497 12.497-32.758 0-45.255l-4.242 4.242Zm-32.583-3.403c10.081-6.585 23.732-5.447 32.583 3.403l4.242-4.242c-10.898-10.899-27.697-12.29-40.106-4.184l3.281 5.023Z" /> <path fill="#000" d="M292.654 245.606a3 3 0 1 1-4.243-4.242l4.243 4.242Zm8.485-8.485-8.485 8.485-4.243-4.242 8.485-8.486 4.243 4.243ZM301.208 254.161a3 3 0 1 1-4.242-4.243l4.242 4.243Zm8.486-8.485-8.486 8.485-4.242-4.243 8.485-8.485 4.243 4.243ZM21.919 246.606a3 3 0 1 0 4.242-4.242l-4.242 4.242Zm-8.486-8.485 8.486 8.485 4.242-4.242-8.485-8.486-4.243 4.243ZM13.364 255.161a3 3 0 1 0 4.243-4.243l-4.243 4.243Zm-8.485-8.485 8.485 8.485 4.243-4.243-8.486-8.485-4.242 4.243Z" /> <path fill="#FF1E1E" d="M113.322 154.665h88.371v13.25h-88.371z" /> <path fill="#000" fill-rule="evenodd" d="M225.3 113.481c17.939 14.394 28.018 37.148 28.018 57.504H191.67c-.087-13.669-11.194-24.723-24.883-24.723h-18.56c-13.689 0-24.796 11.054-24.883 24.723H62c0-20.356 10.078-43.11 28.018-57.504C107.957 99.087 132.289 91 157.659 91c25.37 0 49.701 8.087 67.641 22.481Z" clip-rule="evenodd" /> <circle cx="212.665" cy="197.079" r="8.079" fill="#000" /> <circle cx="104.079" cy="197.079" r="8.079" fill="#000" /> <path fill="#000" d="M179.165 211.683c0 8.21-9.868 17.451-20.845 17.451-10.977 0-20.845-9.241-20.845-17.451 0-8.211 9.868-12.281 20.845-12.281 10.977 0 20.845 4.07 20.845 12.281Z" /> <path stroke="#000" stroke-linecap="round" stroke-width="6" d="M198 417v12M222 417v12M95 417v12M119 417v12" /> <circle cx="158" cy="143" r="140" fill="url(#c)" stroke="#000" stroke-width="6" /> <g clip-path="url(#d)"> <path fill="#F5D949" stroke="#000" stroke-width="6" d="m217.543 305.943.704 1.692 1.826.146 12.818 1.027h.001a.17.17 0 0 1 .059.011l.002.001a.147.147 0 0 1 .037.065.15.15 0 0 1 .008.075l-.001.002c0 .001-.01.017-.041.044h-.001l-9.765 8.365-1.391 1.192.425 1.782 2.981 12.506h.001c.009.04.008.058.008.06l-.001.002a.148.148 0 0 1-.05.056.146.146 0 0 1-.069.031h-.002c-.002-.001-.02-.005-.054-.026l-10.974-6.702-1.564-.955-1.564.955-10.974 6.702a.177.177 0 0 1-.053.025l-.002.001c-.004-.001-.032-.005-.069-.032a.146.146 0 0 1-.051-.056l-.001-.002s-.001-.018.008-.058l.001-.001 2.981-12.506.425-1.782-1.391-1.192-9.765-8.365h-.001c-.031-.027-.04-.043-.041-.044l-.001-.002a.15.15 0 0 1 .008-.075.147.147 0 0 1 .037-.065l.002-.001a.17.17 0 0 1 .059-.011h.001l12.818-1.027 1.826-.146.704-1.692 4.938-11.875a.161.161 0 0 1 .028-.051l.001-.001a.146.146 0 0 1 .076-.016c.047 0 .072.013.076.016l.001.001c.001 0 .012.013.028.051l4.938 11.875Z" /> </g> <path stroke="#000" stroke-linecap="round" stroke-width="16" d="M56.884 247.116A143.01 143.01 0 0 0 158 289a143.002 143.002 0 0 0 101.116-41.884" /> <path stroke="#000" stroke-width="6" d="M65.035 404s25.382-6.618 41.965-6.5c17.059.121 43.035 7.5 43.035 7.5M164.012 403.977s25.961-5.606 42.932-5.472C224.402 398.642 251 405 251 405M25 290l7.769-4.072a57.001 57.001 0 0 0 25.067-26.121L62 251M254.363 252l3.867 7.873a57.002 57.002 0 0 0 25.452 25.746l8.694 4.394" /> <defs> <linearGradient id="a" x1="158" x2="158" y1="0" y2="286" gradientUnits="userSpaceOnUse"> <stop offset=".219" /> <stop offset="1" stop-color="#fff" /> </linearGradient> <linearGradient id="b" x1="254" x2="100" y1="419" y2="325" gradientUnits="userSpaceOnUse"> <stop stop-opacity=".98" /> <stop offset="1" stop-opacity="0" /> </linearGradient> <radialGradient id="c" cx="0" cy="0" r="1" gradientTransform="matrix(165.9998 58.9999 -60.6938 170.7657 210 171)" gradientUnits="userSpaceOnUse"> <stop offset=".771" stop-color="#D9D9D9" stop-opacity="0" /> <stop offset="1" stop-color="#fff" stop-opacity=".63" /> </radialGradient> <clipPath id="d"> <path fill="#fff" d="M189 291h47v45h-47z" /> </clipPath> </defs> </svg> </span> </span> </span> </button> </body> <script> const BUTTON = document.querySelector("button"); const SYNC = document.querySelector("#sync") const TOGGLE = () => { const IS_PRESSED = BUTTON.matches("[aria-pressed=true]"); if (SYNC.checked) document.body.setAttribute("data-dark-mode", IS_PRESSED ? false : true); BUTTON.setAttribute("aria-pressed", IS_PRESSED ? false : true); }; BUTTON.addEventListener("click", TOGGLE); </script> </html>使用方式 复制源代码到空白的html格式文件,在浏览中打开运行即可。
技术教程
# Web前端
易航
1年前
3
42
1
2024-12-27
微信小程序渗透测试——抓包手记
使用工具:Proxifier+Burp Suite + 微信PC端 一、Burp Suite 设置 开启监听本地8080端口,如下图: 图片 使用Burp Suite导出功能导出证书或者浏览器使用代理访问127.0.0.1:8080下载证书,如下图: 图片 图片 安装证书至PC中,如下图: 图片 图片 图片 图片 图片 图片 图片 图片 图片 图片 二、Proxifier 设置 设置代理,将抓包流量转发至本地8080端口:点击配置文件——>代理服务器——>添加,设置如下: 图片 图片 图片 设置代理规则,抓取小程序数据包:点击配置文件——>代理规则——>添加——>在应用程序中填写小程序的进程wechatappex.exe 图片 图片 图片 图片 图片 图片 配置均已完成。 三、演示 演示截图如下,仅演示作用: 图片 图片
技术教程
# 小程序
# 网络安全
易航
1年前
0
150
0
2024-12-27
无需安装 IDE 就可以开发 Android 应用了
导读:Google 正在将 Android Studio 集成到它基于云的开发平台 Project IDX 编辑器之中。图片 大家知道吗?Project IDX 是 Google 的一个基于浏览器的开发环境,很快也将能够用于 Android 开发。 Google 的 Project IDX 是一个基于云的开发环境 (IDE),可在浏览器中为开发者提供代码编辑器。 其优点是不必在 PC 上设置本地开发环境,而是可以在任何浏览器中、从上次中断的地方继续编码。 而现在,我们将很快也将能够从 IDX 环境中运行 Android 开发。 在近日,印度班加罗尔举行的 Google I/O Connect 大会上, Google 宣布他们现在正将 Android Studio与 Project IDX 集成。 图片 Google 提道,IDX 上的 Android Studio 允许开发者直接在浏览器中轻松打开托管在 IDX 上的 Android Studio 项目。 新的 Android 模拟器 Android Studio 是 Google 基于 IntelliJ IDEA 的专业 IDE,用于创建 Android 应用程序。 以前,想要为 Android 进行本机应用程序开发的开发人员必须在其计算机上本地安装 Android Studio,不论你是 macOS、Linux 还是 Windows 系统。 但是如今,随着 Android Studio 集成到 IDX 中,开发者们不再需要安装它。 除了能够在 IDX 编辑器中进行实际编码之外,IDX 还具有内置 Android 模拟器,以便人们可以在开发应用程序时对其进行测试。 图片 目前,IDX 中关于 Android Studio 的信息还很少,但是从 Google 的视频和上面的屏幕截图来看,它看起来与“常规”的Android Studio 还是非常相似的。 IDX 到目前为止来观察,它一直基于 VS Code 编辑器。但不清楚 Android Studio 的 IDX 版本底层是否也是基于 VS Code,或者 Google 是否已将 IntelliJ IDEA 集成到浏览器中。 开发者给了初评 云端Android IDE的这个消息似乎受到开发者初步的好评。 Android Studio 以其“沉重”而闻名,如果不必要将其安装在自己的 PC 上,应该会受到更多移动开发者的欢迎。 图片 如若想要在 Project IDX 中访问 Android Studio,目前需要填写申请表单,将自己列入等待名单,待Google 的同学批准,即可试用。 IDX的地址 https://idx.google.com/android-studio
技术教程
# Android
易航
1年前
0
32
0
2024-12-27
你知道 Python 其实自带了小型数据库吗
DBM(DataBase Manager) DBM(DataBase Manager)是一种文件系统,专门用于键值对的存储,最初是在 Unix 平台实现,现在其它平台也可以用。对于 KV 模型,DBM 提供了一个轻量级、高效的存储解决方案。 总的来说,DBM 具有如下特点: 简单快速:非常简单易用,读取和写入操作都很快,适合存储少量数据。 键值对存储:数据是以键值对形式存储的,你可以像操作 Python 字典一样。 文件存储:数据存在具体的文件中,可以轻松地备份和转移。 不支持复杂查询:如果需要执行复杂查询或需要关系型数据库的功能,DBM 可能不是一个好选择。 而 Python 标准库提供了一个 dbm 模块,它实现了 DBM 文件系统的功能,来看一下它的用法。 import dbm # 第一个参数是文件名 # 第二个参数是模式,有以下几种 # r:只读,要求文件必须存在,默认就是这个模式 # w:可读可写,要求文件必须存在 # c:可读可写,文件不存在会创建,存在则追加 # n:可读可写,文件不存在会创建,存在则清空 # 第三个参数是权限,用八进制数字表示,默认 0o666,即可读可写不可执行 db = dbm.open("store", "c") # 打开文件就可以存储值了,key 和 value 必须是字符串或 bytes 对象 db["name"] = "S せんせい" db["age"] = "18" db[b"corporation"] = "小摩".encode("utf-8") # 关闭文件,将内容写到磁盘上 db.close()非常简单,就像操作字典一样,并且 key 是唯一的,如果存在则替换。执行完后,当前目录会多出一个 store.db 文件。 图片 我们打开它,然后读取刚才写入的键值对。 import dbm db = dbm.open("store", "c") # 获取所有的 key,直接返回一个列表 print(db.keys()) """ [b'corporation', b'name', b'age'] """ # 判断一个 key 是否存在,key 可以是字符串或 bytes 对象 print("name" in db, "NAME" in db) """ True False """ # 获取一个 key 对应的 value,得到的是 bytes 对象 print(db["name"].decode("utf-8")) print(db[b"corporation"].decode("utf-8")) """ S せんせい 小摩 """ # key 如果不存在,会抛出 KeyError,我们可以使用 get 方法 print(db.get("NAME", b"unknown")) """ b'unknown' """ # 当然也可以使用 setdefault 方法,key 不存在时,自动写进去 print(db.setdefault("gender", b"female")) """ b'female' """ print(db["gender"]) """ b'female' """非常简单,当你需要存储的数据量不适合放在内存中,但又没必要引入数据库,那么不妨试试使用 dbm 模块吧。 当然啦,dbm 虽然很方便,但它只能持久化 bytes 对象,字符串也是转成 bytes 对象之后再存储的。所以除了 dbm 之外,还有一个标准库模块 shelve,它可以持久化任意对象。 shelve shelve 的使用方式和 dbm 几乎是一致的,区别就是 shelve 的序列化能力要更强,当然速度自然也就慢一些。 import shelve # 第二个参数表示模式,默认是 c # 因此文件不存在会创建,存在则追加 sh = shelve.open("shelve") sh["name"] = ["S 老师", "高老师", "电烤🐔架"] sh["age"] = {18} sh["job"] = {"tutu": "大学生", "xueer": "医生"} # 关闭文件,刷到磁盘中 sh.close()执行完之后,本地会多出一个 shelve.db 文件,下面来读取它。 import shelve sh = shelve.open("shelve") print(sh["name"]) print(sh["name"][2] == "电烤🐔架") """ ['S 老师', '高老师', '电烤🐔架'] True """ print(sh["age"]) """ {18} """ print(sh["job"]) """ {'tutu': '大学生', 'xueer': '医生'} """ sh.close()读取出来的就是原始的对象,我们可以直接操作它。 然后自定义类的实例对象也是可以的。 import shelve class People: def __init__(self, name, age): self.name = name self.age = age @property def print_info(self): return f"name is {self.name}, age is {self.age}" sh = shelve.open("shelve") p = People("群主", 58) # 将类、和该类的实例对象存储进去 sh["People"] = People sh["p"] = p sh.close()执行完之后,我们打开它。 import shelve sh = shelve.open("shelve") # 需要注意的是,People 是我们自己定义的类 # 如果你想要将其还原出来,那么该类必须要出现在当前的命名空间中 try: sh["People"] except AttributeError as e: print(e) """ Can't get attribute 'People' on <module ...> """ class People: def __init__(self, name, age): self.name = name self.age = age @property def print_info(self): return f"name is {self.name}, age is {self.age}" print(sh["People"] is People) """ True """ print(sh["p"].print_info) """ name is 群主, age is 58 """ print(sh["People"]("群主", 38).print_info) """ name is 群主, age is 38 """这就是 shelve 模块,非常强大,当然它底层也是基于 pickle 实现的。如果你不需要存储复杂的 Python 对象,只需要存储字符串的话,那么还是推荐 dbm。 然后在使用 shelve 的时候,需要注意里面的一个坑。 import shelve # 打开文件,设置键值对 sh = shelve.open("shelve") sh["name"] = "古明地觉" sh["score"] = [80, 80, 80] sh.close() # 重新打开文件,修改键值对 sh = shelve.open("shelve") sh["name"] = "芙兰朵露" sh["score"].append(90) sh.close() # 再次重新打开文件,查看键值对 sh = shelve.open("shelve") print(sh["name"]) print(sh["score"]) """ 芙兰朵露 [80, 80, 80] """ sh.close()第一次打开文件创建两个键值对,第二次打开文件将键值对修改,第三次打开文件查看键值对。但是我们发现 sh["name"] 变了,而 sh["score"] 却没变,这是什么原因? 当我们修改 name 时,采用的是直接赋值的方式,会将原本内存里的值给替换掉。而修改 score 时,是在原有值的基础上做 append 操作,它的内存地址并没有变。 所以可变对象在本地进行修改,shelve 默认是不会记录的,除非创建新的对象,并把原有的对象给替换掉。所以 sh["score"].append(90) 之后,sh["score"] 仍是 [80, 80, 80],而不是 [80, 80, 80, 90]。 因为 shelve 没有记录对象自身的修改,如果想得到期望的结果,一种方法是把对象整体换掉。也就是让 sh["score"] = [80, 80, 80, 90],这样等于是创建了一个新的对象并重新赋值,是可行的。 或者你在打开文件的时候,多指定一个参数 writeback。 import shelve # 打开文件,设置键值对 sh = shelve.open("shelve") sh["name"] = "古明地觉" sh["score"] = [80, 80, 80] sh.close() # 重新打开文件,修改键值对 sh = shelve.open("shelve", writeback=True) sh["name"] = "芙兰朵露" sh["score"].append(90) sh.close() # 再次重新打开文件,查看键值对 sh = shelve.open("shelve") print(sh["name"]) print(sh["score"]) """ 芙兰朵露 [80, 80, 80, 90] """ sh.close()可以看到都发生改变了,但这个参数会导致额外的内存消耗。当指定 writeback=True 的时候,shelve 会将读取的对象都放到一个内存缓存当中。比如我们操作了 20 个持久化的对象,但只修改了一个,剩余的 19 个只是查看并没有做修改,但当 sh.close() 的时候,会将这 20 个对象都写回去。 因为 shelve 不知道你会对哪个对象做修改,所以不管你是查看还是修改,都会放到缓存当中,然后再一次性都写回去。这样就会造成两点影响: shelve 会把我们使用的对象放到内存的另一片空间中,等于是额外拷贝了一份。 虽然操作了 N 个对象,但只修改了 1 个,而 shelve 会把 N 个对象都重新写回去,从而造成性能上的问题,导致效率降低。 因此加不加这个参数,由具体情况决定。 综上所述,Python 算是自带了小型数据库,看看能不能在合适的场景中把它用上。
技术教程
# Python
# 数据库
易航
1年前
0
26
0
上一页
1
...
4
5
6
...
17
下一页