包含关键字 po 的文章 - 第 2 页 - 空痕博客 - 编程学习分享
首页
小记
php
python
uniapp
前端
其他
机器人
QQ机器人
项目
功能库
应用
其他页面
友情链接
用户留言
联系空痕
热门文章
PHP搭建QQ机器人(QQ官方)
解决三个导致 Google Antigravity 无法登录的问题
移动云盘分享的链接信息获取接口请求体/响应体加密及解密
下载文件到指定文件夹
上传文件到夸克网盘python代码
标签搜索
uniapp
python
PHP
UTS
uniapp-x
模板
html
VUE
夸克网盘
移动云盘
APP
KongHen
机器人
QQ
ID3
pyinstaller
redis
Echarts
邮箱
js
发布
登录
注册
找到
20
篇与
po
相关的结果
- 第 2 页
2025-10-24
UTS编写字符串编解码/加密插件(安卓及鸿蒙端)
全局说明 编写说明 uts在安卓端编译为kotlin,所以,使用可以使用安卓自带库+kotlin的方法来实现 uts在鸿蒙端编译为ArkTs,ArkTs和UTS很相似,包括一些方法都一样,所以可以直接从ArkTs的文档里复制代码,稍微修改即可使用。 使用的库 安卓端 import MessageDigest from 'java.security.MessageDigest'; import BigInteger from 'java.math.BigInteger'; import Base64 from 'java.util.Base64'; 鸿蒙端 import util from '@ohos.util'; import { cryptoFramework } from '@kit.CryptoArchitectureKit';插件接口定义 /** * interface.uts * uts插件接口定义文件,按规范定义接口文件可以在HBuilderX中更好的做到语法提示 */ /** * 哈希算法枚举 */ export type HashAlgorithm = | "MD5" | "SHA1" | "SHA224" | "SHA256" | "SHA384" | "SHA512" /** * 哈希加密返回结果 */ export type HashResult = { hash: string } /** * 哈希加密函数定义 */ export type HashFunction = (input: string, algorithm: HashAlgorithm) => string1. Base64编解码 安卓端 /** * BASE64编码方法 * * @param input 输入字符串 * @return BASE64加密后的字符串 */ export const Base64Encode = function (input: string) : string { try { // 将字符串转换为字节数组 // toByteArray()为kotlin的方法 const inputBytes = input.toByteArray(); // 使用Base64编码器进行编码 const encodedBytes = Base64.getEncoder().encodeToString(inputBytes); // 将编码后的字节数组转换为字符串 return encodedBytes; } catch (e) { console.error("BASE64加密错误:", e); return ""; } } /** * BASE64解码方法 * * @param input 输入字符串 * @return BASE64解密后的字符串 */ export const Base64Decode = function (input: string) : string { try { // 将Base64字符串转换为字节数组 const decodedBytes = Base64.getDecoder().decode(input); // 将Java字节数组转换为UTS字符串 return new String(decodedBytes); } catch (e) { console.error("BASE64解密错误:", e); return ""; } } 鸿蒙端 /** * BASE64编码方法 * * @param input 输入字符串 * @return BASE64加密后的字符串 */ export const Base64Encode = function (input: string) : string { let textEncoder = new util.TextEncoder("utf-8"); let uint8Array = textEncoder.encodeInto(input); let base64Helper = new util.Base64Helper(); return base64Helper.encodeToStringSync(uint8Array); } /** * BASE64解码方法 * * @param input 输入字符串 * @return BASE64解密后的字符串 */ export const Base64Decode = function (input: string) : string { let Base64Helper = new util.Base64Helper(); let arr = Base64Helper.decodeSync(input) let textDecoder = util.TextDecoder.create('utf-8'); return textDecoder.decodeToString(arr); } 消息摘要计算 HASH加密使用统一方法,包含MD5、SHA1、SHA224、SHA256、SHA384、SHA512 安卓端 /** * 统一哈希加密方法 * * @param input 输入字符串 * @param algorithm 哈希算法枚举 * @return 哈希加密后的十六进制字符串 */ export const hash : HashFunction = function (input : string, algorithm: HashAlgorithm) : string { try { // 创建MessageDigest实例 const md = MessageDigest.getInstance(algorithm); // 输入数据转化为字节数组 const dataArray = input.toByteArray() // 计算哈希值 const hashBytes = md.digest(dataArray); // 转换为十六进制字符串 const result = BigInteger(1, hashBytes).toString(16) return result; } catch (e) { // 方法出错时返回空字符串 console.error(`${algorithm}加密错误:`, e); return ""; } }鸿蒙端 /** * 统一哈希加密方法 * * @param input 输入字符串 * @param algorithm 哈希算法枚举 * @return 哈希加密后的十六进制字符串 */ export const hash : HashFunction = function (input : string, algorithm: HashAlgorithm) : string { try { // 创建哈希实例 let md = cryptoFramework.createMd(algorithm); // 使用同步方法更新数据 let textEncoder = util.TextEncoder.create('utf-8'); let dataBlob : cryptoFramework.DataBlob = { data: textEncoder.encodeInto(input); }; md.updateSync(dataBlob); // 使用同步方法计算摘要 let mdResult : cryptoFramework.DataBlob = md.digestSync(); // 转换为十六进制字符串 let result = Array.from(mdResult.data).map(byte => byte.toString(16).padStart(2, '0')).join(''); return result; } catch (e) { // 方法出错时返回空字符串 // console.error(`${algorithm}加密错误:`, e); return ""; } }规范调用方法 这里安卓端和鸿蒙端相同 // MD5加密 export const MD5 = function (input: string) : string { return hash(input, 'MD5') } // SHA1加密 export const SHA1 = function (input: string) : string { return hash(input, 'SHA1') } // SHA224加密 export const SHA224 = function (input: string) : string { return hash(input, 'SHA224') } // SHA256加密 export const SHA256 = function (input: string) : string { return hash(input, 'SHA256') } // SHA384加密 export const SHA384 = function (input: string) : string { return hash(input, 'SHA384') } // SHA512加密 export const SHA512 = function (input: string) : string { return hash(input, 'SHA512') }使用方法 import * as KhCrypto from '@/uni_modules/kh-crypto' const input = ref<string>('待加密字符串'); const output = ref<string>('') // base64编码 output.value = KhCrypto.Base64Encode(inputText.value) // base64解码 output.value = KhCrypto.Base64Decode(inputText.value) // MD5加密 output.value = KhCrypto.MD5(inputText.value) // SHA1加密 output.value = KhCrypto.SHA1(inputText.value) // SHA224加密 output.value = KhCrypto.SHA224(inputText.value) // SHA256加密 output.value = KhCrypto.SHA256(inputText.value) // SHA384加密 output.value = KhCrypto.SHA384(inputText.value) // SHA512加密 output.value = KhCrypto.SHA512(inputText.value)插件源码 kh-crypto - DCloud插件市场 参考文档 在uts中如何将字符串转换为ByteArray Base64Helper - 鸿蒙开发API参考 消息摘要计算介绍及算法规格 - 鸿蒙开发指南
uniapp
uniapp-x
功能库
uts
# uniapp
# UTS
# uniapp-x
# 鸿蒙
KongHen02
1年前
0
64
0
2025-10-13
完美解决请求跨域问题
问题说明 1. 什么是跨域问题? 跨域问题是由浏览器的同源策略(Same-Origin Policy)引起的一种安全限制。当网页尝试访问不同源(协议、域名、端口任一不同)的资源时,浏览器会阻止这种请求。 2. 同源策略定义 两个URL在以下三个方面完全相同时才属于同源: 协议(Protocol):http、https等 域名(Domain):www.example.com 端口(Port):80、443等 3. 常见的跨域场景 // 同源示例 http://example.com/app1 --> http://example.com/app2 // 同源 // 跨域示例 http://example.com --> https://example.com // 协议不同 http://test.example.com --> http://api.example.com // 域名不同 http://example.com:80 --> http://example.com:8080 // 端口不同4. 浏览器端表现 // 预检请求 Access to XMLHttpRequest at 'http://api.example.com' from origin 'http://test.example.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. // 正式请求 Access to XMLHttpRequest at 'http://api.example.com' from origin 'http://test.example.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.跨域问题.png图片 跨域检测 跨域检测工具:跨域测试工具 解决方法 1. 服务端配置允许跨域(后端属于自己) 基于宝塔面板配置 最新版宝塔面板(11.0.0+) 最新版宝塔配置非常简单,直接在站点设置里开启允许跨域即可。 配置步骤: 打开宝塔面板“网站”,点击对应的站点 点击“其他设置” - “跨域访问CORS配置” - “状态” - 开启 - “保存” 即可 步骤演示图片 低版本宝塔面板(< 11.0.0) 低版本需要修改站点的配置文件,略微麻烦。 配置步骤: 打开宝塔面板“网站”,点击对应的站点 点击“配置文件”,添加以下内容即可 # 解决跨域问题--START add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods GET,POST,OPTIONS,PUT,DELETE; add_header Access-Control-Allow-Headers DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization; add_header Access-Control-Expose-Headers Content-Length,Content-Range; location / { # 处理 OPTIONS 预检请求 if ($request_method = 'OPTIONS') { add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods GET,POST,OPTIONS,PUT,DELETE; add_header Access-Control-Allow-Headers DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization; add_header Access-Control-Expose-Headers Content-Length,Content-Range; add_header Access-Control-Max-Age 1728000; add_header Content-Type text/plain; add_header Content-Length 0; return 204; } } # 解决跨域问题--END步骤演示图片 存在的问题 需要删除自己代码里的允许跨域配置,否则会出现跨域冲突,出现错误。 // 配置冲突 Access to XMLHttpRequest at 'https://test.khkj6.com/' from origin 'https://tool.khkj.xyz' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values '*, *', but only one is allowed.配置冲突图片 2. 使用代理(服务端不属于自己) 跨域是浏览器端检测请求不同源,对请求进行拦截,所以,只要不使用浏览器发送请求就可以解决。 使用自己同源的域名或配置了允许跨域的域名进行代理 以下提供最基础的php演示 $ch = curl_init(); // POST 数据 $postData = [ 'name' => '张三', 'email' => 'zhangsan@example.com', 'age' => 25 ]; curl_setopt_array($ch, [ CURLOPT_URL => "https://api.example.com/users", CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => http_build_query($postData), // 表单格式 CURLOPT_HTTPHEADER => [ 'Content-Type: application/x-www-form-urlencoded', ] ]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); echo "状态码: " . $httpCode . "\n"; echo "响应: " . $response;使用非浏览器发送请求 在app、小程序等环境中,不会出现跨域问题。 3. 浏览器禁用安全策略(仅开发环境) --disable-web-security --user-data-dir=文件夹路径配置步骤: 以chrome浏览器为例 在任意位置创建一个文件夹(用于存储禁用安全策略的浏览器数据) 示例路径:C:\MyChromeDevUserData 完整代码:--disable-web-security --user-data-dir=C:\MyChromeDevUserData 复制文件夹路径 找到chrome的安装目录 为chrome.exe创建快捷方式 打开创建的快捷方式的属性 打开属性图片 在属性 - 目标后方添加代码 f0ad4e 修改目标路径图片 使用新建的快捷方式进入,不会触发跨域问题
其他
# PHP
# 跨域
# 浏览器
KongHen02
1年前
0
182
0
2025-10-12
蓝奏云 python sdk库
蓝奏云 Python 库使用文档 1. 配置与初始化 首先,准备 config.yaml 配置文件,内容示例: lanzou: username: "你的用户名" password: "你的密码"在代码中读取配置并初始化蓝奏云会话: import yaml from Lanzou import LanzouSession # 读取配置文件 with open("config.yaml", "r", encoding="utf-8") as f: config = yaml.safe_load(f) lanzou_conf = config["lanzou"] # 创建蓝奏云基础实例 session = LanzouSession() # 登录获取cookie status, result = session.login(lanzou_conf["username"], lanzou_conf["password"])2. 文件管理 2.1 创建文件管理实例 from Lanzou import LanzouFileManager file_manager = LanzouFileManager(session)2.2 重命名文件 status, result = file_manager.rename_file("文件ID", "新文件名.png") # 返回示例: # True { # "zt": 1, # "info": "重命名成功", # "text": None, # "dat": None # } # False { # "zt": 0, # "info": "会员已过期,无法使用", # "text": None, # "dat": None # }2.3 删除文件 status, result = file_manager.delete_file("文件ID") # 返回示例: # True { # "zt": 1, # "info": "已删除", # "text": None, # "dat": None # }2.4 上传文件 status, result = file_manager.upload_file("本地文件路径", "上传文件名.txt", "目标文件夹ID") # 返回示例: # True { # "zt": 1, # "info": "上传成功", # "text": [ # { # "icon": "txt", # "id": "246766304", # "f_id": "iYYAN31w12je", # "name_all": "上传测试.txt", # "name": "上传测试.txt", # "size": "18.0 B", # "time": "0 秒前", # "downs": "0", # "onof": "0", # "is_newd": "https://wwa.lanzouq.com" # } # ] # }2.5 移动文件 status, result = file_manager.move_file("文件ID", "目标文件夹ID") # 返回示例: # True { # "zt": 1, # "info": "移动成功", # "text": None, # "dat": None # }2.6 设置文件密码 status, result = file_manager.set_file_pwd("文件ID", "密码", "1") # 返回示例: # True { # "zt": 1, # "info": "设置成功", # "text": None, # "dat": None # }3. 文件夹管理 3.1 创建文件夹管理实例 from Lanzou import LanzouFolderManager folder_manager = LanzouFolderManager(session)3.2 创建文件夹 status, result = folder_manager.create_folder("文件夹名称", "父文件夹ID", "文件夹描述") # 返回示例: # True { # "zt": 1, # "info": "创建成功", # "text": "12296591", # "dat": None # }3.3 删除文件夹 status, result = folder_manager.delete_folder("文件夹ID") # 返回示例: # True { # "zt": 1, # "info": "删除成功", # "text": None, # "dat": None # }3.4 获取文件夹信息 status, result = folder_manager.get_folder_info("文件夹ID") # 返回示例: # True { # "zt": 1, # "info": { # "name": "测试2", # "des": "测试文件夹2", # "pwd": "1vo0", # "onof": "1", # "taoc": "", # "is_newd": "https://wwa.lanzouq.com", # "new_url": "https://wwa.lanzouq.com/b0rafeg1e" # }, # "text": None, # "dat": None # }3.5 修改文件夹信息 status, result = folder_manager.set_folder_info("文件夹ID", "新名称", "新描述") # 返回示例: # True { # "zt": 1, # "info": "成功修改", # "text": None, # "dat": None # }3.6 修改文件夹密码 status, result = folder_manager.set_folder_pwd("文件夹ID", "密码", "1") # 返回示例: # True { # "zt": 1, # "info": "修改成功", # "text": None, # "dat": None # }3.7 获取文件夹列表 status, result = folder_manager.get_folder_list("父文件夹ID") # 返回示例: # True { # "zt": 1, # "info": [ # { # "name": "测试", # "folder_des": "[测试文件夹]", # "folderid": 12295088, # "now": 1 # } # ], # "text": [ # { # "onof": "1", # "folderlock": "0", # "is_lock": "0", # "is_copyright": "0", # "name": "修改测试2", # "fol_id": "12295254", # "folder_des": "[修改测试文件夹2...]" # } # ], # "dat": null # }3.8 获取文件列表 status, result = folder_manager.get_file_list("文件夹ID") # 返回示例: # True { # "zt": 1, # "info": 1, # "text": [ # { # "icon": "jpg", # "id": "246767298", # "name_all": "EB9DA95273BC463B238A14588B7E6E8C.jpg", # "name": "EB9DA95273BC463B238A14588B7E6E8C.jpg", # "size": "342.3 K", # "time": "24 分钟前", # "downs": "0", # "onof": "0", # "is_lock": "0", # "filelock": "0", # "is_copyright": 0, # "is_bakdownload": 0, # "bakdownload": "0", # "is_des": 0, # "is_ico": 0 # } # ], # "dat": null # }4. 分享链接管理 4.1 创建分享管理实例 from Lanzou import LanzouShareManager share_manager = LanzouShareManager(session)4.2 获取文件分享链接 status, result = share_manager.get_file_link("文件ID") # 返回示例: # True { # "zt": 1, # "info": { # "pwd": "bofq", # "onof": "1", # "f_id": "it02C31w1u5i", # "taoc": "", # "is_newd": "https://wnwgongzuoshi.lanzouq.com" # }, # "text": None, # "dat": None # }4.3 获取文件夹分享链接 status, result = share_manager.get_folder_link("文件夹ID") # 返回示例: # True { # "zt": 1, # "info": { # "pwd": "bofq", # "onof": "1", # "f_id": "it02C31w1u5i", # "taoc": "", # "is_newd": "https://wnwgongzuoshi.lanzouq.com" # }, # "text": None, # "dat": None # }5. 他人分享链接下载 5.1 创建下载管理实例 from Lanzou import LanzouDownManager lanzouDown = LanzouDownManager()5.2 获取文件夹参数 status = lanzouDown.get_folder_params("分享链接URL")5.3 获取文件及文件夹列表 status, result = lanzouDown.get_file_list(url="分享链接URL", page=1)5.4 获取文件信息(包含下载链接) status, result = lanzouDown.get_file_info("文件分享链接", pwd="密码", final=True) # 返回示例: # True { # "title": "文件名称.apk", # "size": "57.0 M", # "author": "KongHen02", # "desc": "测试描述", # "url": "https://developer-oss.lanrar.com/file/...", # "down": "" # }5.5 通过下载链接获取下载直链 status, result = lanzouDown.get_final_url("下载链接")6. 打印输出 所有接口返回均为 (status, result),可直接打印: import json print(status, json.dumps(result, indent=4))7. 其他说明 各接口返回状态 status 为布尔值,True 表示成功,False 表示失败 返回结果中的 zt 字段:1 表示成功,0 表示失败 info 字段包含操作结果的详细信息 text 字段通常包含文件或文件夹的详细信息 分享链接管理需要用户登录后才能使用 他人分享链接下载不需要登录即可使用 如需更详细的参数说明或扩展用法,请参考源码或补充提问。 代码下载 cloud_driver_sdk 参考文献 openList
功能库
# python
# 蓝奏云
KongHen02
1年前
0
47
0
2025-08-22
故障风格404页面
效果演示 点击查看在线演示 图片演示图片 完整代码 <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>系统故障 - 404</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { background: #0a0a0a; font-family: 'Courier New', monospace; height: 100vh; overflow: hidden; display: flex; align-items: center; justify-content: center; color: #00ff41; cursor: crosshair; } .matrix-bg { position: absolute; width: 100%; height: 100%; opacity: 0.1; background: repeating-linear-gradient( 0deg, transparent, transparent 2px, #00ff41 2px, #00ff41 4px ); animation: scan 8s linear infinite; } @keyframes scan { 0% { transform: translateY(-100%); } 100% { transform: translateY(100%); } } .container { text-align: center; position: relative; z-index: 10; } .error-code { font-size: 120px; font-weight: bold; position: relative; display: inline-block; color: #fff; letter-spacing: 10px; animation: flicker 0.5s infinite alternate; } .error-code::before, .error-code::after { content: "404"; position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: transparent; overflow: hidden; } .error-code::before { left: 2px; text-shadow: -2px 0 #ff00c8; animation: glitch-1 0.3s infinite ease-in-out alternate-reverse; clip: rect(44px, 450px, 56px, 0); } .error-code::after { left: -2px; text-shadow: -2px 0 #00ffff, 2px 2px #ff00c8; animation: glitch-2 0.3s infinite ease-in-out alternate-reverse; clip: rect(44px, 450px, 56px, 0); } @keyframes glitch-1 { 0% { clip: rect(31px, 9999px, 94px, 0); } 20% { clip: rect(112px, 9999px, 76px, 0); } 40% { clip: rect(85px, 9999px, 77px, 0); } 60% { clip: rect(62px, 9999px, 34px, 0); } 80% { clip: rect(97px, 9999px, 89px, 0); } 100% { clip: rect(53px, 9999px, 47px, 0); } } @keyframes glitch-2 { 0% { clip: rect(65px, 9999px, 119px, 0); } 20% { clip: rect(52px, 9999px, 74px, 0); } 40% { clip: rect(4px, 9999px, 78px, 0); } 60% { clip: rect(100px, 9999px, 19px, 0); } 80% { clip: rect(22px, 9999px, 98px, 0); } 100% { clip: rect(89px, 9999px, 113px, 0); } } @keyframes flicker { 0%, 19%, 21%, 23%, 25%, 54%, 56%, 100% { text-shadow: 0 0 5px #00ff41, 0 0 10px #00ff41, 0 0 20px #00ff41; } 20%, 22%, 24%, 55% { text-shadow: none; } } .error-message { font-size: 18px; color: #ff0040; margin: 20px 0; animation: pulse 2s infinite; text-transform: uppercase; letter-spacing: 3px; } @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } } .home-button { display: inline-block; padding: 15px 30px; margin-top: 30px; border: 2px solid #00ff41; background: transparent; color: #00ff41; text-decoration: none; text-transform: uppercase; letter-spacing: 2px; position: relative; overflow: hidden; transition: all 0.3s; font-family: 'Courier New', monospace; } .home-button:hover { color: #0a0a0a; box-shadow: 0 0 20px #00ff41; } .home-button::before { content: ''; position: absolute; top: 0; left: -100%; width: 100%; height: 100%; background: #00ff41; transition: left 0.3s; z-index: -1; } .home-button:hover::before { left: 0; } .noise { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: radial-gradient(circle, transparent 20%, rgba(255,255,255,0.03) 20.1%, transparent 21%), radial-gradient(circle, transparent 40%, rgba(255,255,255,0.03) 40.1%, transparent 41%); animation: noise 0.5s steps(10) infinite; pointer-events: none; } @keyframes noise { 0%, 100% { transform: translate(0); } 10% { transform: translate(-2px, -2px); } 20% { transform: translate(2px, 2px); } 30% { transform: translate(-2px, 2px); } 40% { transform: translate(2px, -2px); } 50% { transform: translate(-2px, -2px); } 60% { transform: translate(2px, 2px); } 70% { transform: translate(-2px, 2px); } 80% { transform: translate(2px, -2px); } 90% { transform: translate(-2px, -2px); } } .system-info { position: absolute; bottom: 20px; left: 20px; font-size: 12px; color: #666; font-family: monospace; animation: typewriter 3s steps(30) 1; } @keyframes typewriter { from { width: 0; } to { width: 100%; } } @media (max-width: 768px) { .error-code { font-size: 80px; } .error-message { font-size: 14px; } } </style> </head> <body> <div class="matrix-bg"></div> <div class="noise"></div> <div class="container"> <h1 class="error-code">404</h1> <p class="error-message">系统故障 - 页面失踪</p> <p style="color: #666; margin-top: 10px;">检测到异常活动,启动安全协议</p> <a href="https://www.khkj6.com" class="home-button">返回安全区</a> </div> <script> // 随机故障效果 setInterval(() => { document.body.style.filter = `hue-rotate(${Math.random() * 360}deg)`; setTimeout(() => { document.body.style.filter = 'none'; }, 100); }, 3000); // 鼠标追踪效果 document.addEventListener('mousemove', (e) => { const x = e.clientX / window.innerWidth; const y = e.clientY / window.innerHeight; const glitch = document.querySelector('.error-code'); glitch.style.transform = `translate(${x * 4}px, ${y * 4}px)`; }); </script> </body> </html>
模板
# 模板
# html
# 404
KongHen02
1年前
0
99
0
2025-08-21
uniapp-x实现自定义tabbar
uniapp-x自带导航栏位置固定,且UI无法修改。如果需要适配自己的应用UI及色彩就需要自定义tabbar。 实现说明 将tabbar写入主页面,需要显示的页面作为组件引入。 示例样式 演示示例图片 实现方法 使用swiper实现 说明: 所有页面一次性加载 允许左右滑动 优点:允许滑动切换,用户体验升级 演示代码 <template> <!-- 页面内容区域 --> <swiper style="flex: 1;" :current="selectedIndex" @change="swiperChange"> <swiper-item item-id="index"> <IndexPage></IndexPage> </swiper-item> <swiper-item item-id="more"> <MorePage></MorePage> </swiper-item> <swiper-item item-id="user"> <UserPage></UserPage> </swiper-item> </swiper> <!-- tabber区域 --> <view class="tab-bar-container"> <view v-for="(item, index) in tabList" class="tab-bar-item" @click="switchTab(index)"> <image class="tab-bar-icon" :src="(selectedIndex === index ? item.s_icon : item.icon)"></image> <text class="tab-bar-text" :style="'color:' + (selectedIndex === index ? '#F59E0B' : '#999999') +';'">{{ item.name }}</text> </view> </view> </template> <script setup lang="uts"> // 导入页面 import IndexPage from "./tabbar/index.uvue" import MorePage from "./tabbar/more.uvue" import UserPage from "./tabbar/user.uvue" // tabbar接口类型 type TabInfo = { name : string, icon : string, s_icon : string } // 页面列表 const tabList = reactive<TabInfo[]>([ { name: "首页", icon: "/static/tabbar/home.png", s_icon: "/static/tabbar/home_selected.png" }, { name: "活动", icon: "/static/tabbar/more.png", s_icon: "/static/tabbar/more_selected.png" }, { name: "我的", icon: "/static/tabbar/user.png", s_icon: "/static/tabbar/user_selected.png" } ]) // 选中的页面 const selectedIndex = ref<number>(0) // swiper切换 const swiperChange = (e: UniSwiperChangeEvent) => { let index = e.detail.current if (selectedIndex.value === index) return selectedIndex.value = index } // 页面切换 const switchTab = (index : number) => { if (selectedIndex.value === index) return selectedIndex.value = index } </script> <style lang="scss"> .tab-bar-container { position: fixed; bottom: 60rpx; width: 80%; left: 10%; z-index: 999; display: flex; flex-direction: row; justify-content: space-around; height: 120rpx; border-radius: 60rpx; box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1); background: rgba(255, 255, 255, 0.4); } .tab-bar-item { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 15rpx 40rpx; } .tab-bar-icon { width: 44rpx; height: 44rpx; margin-bottom: 8rpx; } .tab-bar-text { font-size: 24rpx; } </style>官方示例 说明: 单次只加载一个页面 加载成功后使用v-show控制显示/隐藏,不重复加载(官方使用CSS属性visibility控制,测试不行) 优点:分页加载,减小单次加载压力(如果页面DOM多的话) 演示代码 <template> <!-- 页面内容区域 --> <view style="flex: 1;"> <IndexPage v-if="tabList[0].init" v-show="selectedIndex==0"></IndexPage> <MorePage v-if="tabList[1].init" v-show="selectedIndex==1"></MorePage> <MorePage v-if="tabList[2].init" v-show="selectedIndex==2"></MorePage> </view> <!-- tabber区域 --> <view class="tab-bar-container"> <view v-for="(item, index) in tabList" class="tab-bar-item" @click="switchTab(index)"> <image class="tab-bar-icon" :src="(selectedIndex === index ? item.s_icon : item.icon)"></image> <text class="tab-bar-text" :style="'color:' + (selectedIndex === index ? '#F59E0B' : '#999999') +';'">{{ item.name }}</text> </view> </view> </template> <script setup lang="uts"> // 导入页面 import IndexPage from "./tabbar/index.uvue" import MorePage from "./tabbar/more.uvue" import UserPage from "./tabbar/user.uvue" // tabbar接口类型 type TabInfo = { init: boolean, name : string, icon : string, s_icon : string } // 页面列表 const tabList = reactive<TabInfo[]>([ { init: true, name: "首页", icon: "/static/tabbar/home.png", s_icon: "/static/tabbar/home_selected.png" }, { init: false, name: "更多", icon: "/static/tabbar/more.png", s_icon: "/static/tabbar/more_selected.png" }, { init: false, name: "我的", icon: "/static/tabbar/user.png", s_icon: "/static/tabbar/user_selected.png" } ]) // 选中的页面 const selectedIndex = ref<number>(0) // 页面切换 const switchTab = (index : number) => { if (selectedIndex.value === index) return if (!tabList[index].init) { tabList[index].init = true } selectedIndex.value = index } </script> <style lang="scss"> .tab-bar-container { position: fixed; bottom: 60rpx; width: 80%; left: 10%; z-index: 999; display: flex; flex-direction: row; justify-content: space-around; height: 120rpx; border-radius: 60rpx; box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1); background: rgba(255, 255, 255, 0.4); } .tab-bar-item { display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 15rpx 40rpx; } .tab-bar-icon { width: 44rpx; height: 44rpx; margin-bottom: 8rpx; } .tab-bar-text { font-size: 24rpx; } </style>其他方法 使用share-element组件实现 复制官方代码,偶先切换页面组件闪动问题。官方uniapp-xapp的demo测试正常,不知道申明原因。 使用components组件+share-element组件实现的tabbar组件实现,tabbar组件会出现与页面移入方向反向滑动的动画 share-element文档 静态资源 tabbar图标(png) 下载地址:https://www.khkj6.com/usr/uploads/2025/08/2337268233.zip 提取码:
uniapp-x
# VUE
# uniapp-x
# tabbar
# swiper
KongHen02
1年前
0
158
1
上一页
1
2
3
4
下一页
易航博客