当前位置: 首页 > news >正文

Vue3骨架屏(Skeleton)

效果如下图:在线预览

在这里插入图片描述
在这里插入图片描述

APIs

参数说明类型默认值必传
animated是否展示动画效果booleantruefalse
button是否使用按钮占位图boolean | SkeletonButtonPropsfalsefalse
avatar是否显示头像占位图boolean | SkeletonAvatarPropsfalsefalse
input是否使用输入框占位图boolean | SkeletonInputPropsfalsefalse
image是否使用图像占位图booleanfalsefalse
title是否显示标题占位图boolean | SkeletonTitlePropstruefalse
paragraph是否显示段落占位图boolean | SkeletonParagraphPropstruefalse
loadingtrue 时,显示占位图,反之则直接展示子组件booleantruefalse

SkeletonButtonProps Type

名称说明类型必传
shape指定按钮的形状‘default’ | ‘round’ | ‘circle’false
size设置按钮的大小‘default’ | ‘small’ | ‘large’false
block将按钮宽度调整为其父宽度的选项booleanfalse

SkeletonAvatarProps Type

名称说明类型必传
shape指定头像的形状‘circle’ | ‘square’false
size设置头像占位图的大小number | ‘default’ | ‘small’ | ‘large’false

SkeletonInputProps Type

名称说明类型必传
size设置输入框的大小‘default’ | ‘small’ | ‘large’false

SkeletonTitleProps Type

名称说明类型必传
width设置标题占位图的宽度number | stringfalse

SkeletonParagraphProps Type

名称说明类型必传
rows设置段落占位图的行数number | stringfalse
width设置段落占位图的宽度,若为数组时则为对应的每行宽度,反之则是最后一行的宽度number | string | Array<number|string>false

创建骨架屏组件Skeleton.vue

<script setup lang="ts">
import { computed } from 'vue'interface SkeletonButtonProps {shape?: 'default'|'round'|'circle' // 指定按钮的形状size?: 'default'|'small'|'large' // 设置按钮的大小block?: boolean // 将按钮宽度调整为其父宽度的选项
}
interface SkeletonAvatarProps {shape?: 'circle'|'square' // 指定头像的形状size?: number|'default'|'small'|'large' // 设置头像占位图的大小
}
interface SkeletonInputProps {size: 'default'|'small'|'large' // 设置输入框的大小
}
interface SkeletonTitleProps {width?: number|string // 设置标题占位图的宽度
}
interface SkeletonParagraphProps {rows?: number|string // 设置段落占位图的行数width?: number|string|Array<number|string>	// 设置段落占位图的宽度,若为数组时则为对应的每行宽度,反之则是最后一行的宽度
}
interface Props {animated?: boolean // 是否展示动画效果button?: boolean|SkeletonButtonProps // 是否使用按钮占位图avatar?: boolean|SkeletonAvatarProps // 是否显示头像占位图input?: boolean|SkeletonInputProps // 是否使用输入框占位图image?: boolean // 是否使用图像占位图title?: boolean|SkeletonTitleProps // 是否显示标题占位图paragraph?: boolean|SkeletonParagraphProps // 是否显示段落占位图loading?: boolean // 为 true 时,显示占位图,反之则直接展示子组件
}
const props = withDefaults(defineProps<Props>(), {animated: true,button: false,image: false,avatar: false,input: false,title: true,paragraph: true,loading: true
})
const buttonSize = computed(() => {if (typeof props.button === 'object') {if (props.button.size === 'large') {return 40}if (props.button.size === 'small') {return 24}return 32}
})
const titleTop = computed(() => {if (typeof props.avatar === 'boolean') {return 8} else {if (typeof props.avatar.size === 'number') {return (props.avatar.size - 16) / 2} else {const topMap = {default: 8,small: 4,large: 12}return topMap[props.avatar.size || 'default']}}
})
const titleWidth = computed(() => {if (typeof props.title === 'boolean') {return '38%'} else {if (typeof props.title.width === 'number') {return props.title.width + 'px'}return props.title.width || '38%'}
})
const paragraphRows = computed(() => {if (typeof props.paragraph === 'boolean') {return 3}return props.paragraph.rows
})
const paragraphWidth = computed(() => {if (typeof props.paragraph === 'boolean') {return Array(paragraphRows.value)} else {if (Array.isArray(props.paragraph.width)) {return props.paragraph.width.map((width: number|string) => {if (typeof width === 'number') {return width + 'px'} else {return width}})} else if (typeof props.paragraph.width === 'number') {return Array(paragraphRows.value).fill(props.paragraph.width + 'px')} else {return Array(paragraphRows.value).fill(props.paragraph.width)}}
})
</script>
<template><divv-if="loading":class="['m-skeleton', {'m-skeleton-avatar': avatar, 'm-skeleton-animated': animated}]":style="`--button-size: ${buttonSize}px; --title-top: ${titleTop}px;`"><spanv-if="button":class="['u-skeleton-button',{'u-button-round': typeof button !== 'boolean' && button.shape === 'round','u-button-circle': typeof button !== 'boolean' && button.shape === 'circle','u-button-sm': typeof button !== 'boolean' && button.size === 'small','u-button-lg': typeof button !== 'boolean' && button.size === 'large','u-button-block': typeof button !== 'boolean' && button.shape !== 'circle' && button.block,}]"></span><span:class="['u-skeleton-input',{'u-input-sm': typeof input !== 'boolean' && input.size === 'small','u-input-lg': typeof input !== 'boolean' && input.size === 'large',}]" v-if="input"></span><div class="m-skeleton-image" v-if="image"><svg viewBox="0 0 1098 1024" xmlns="http://www.w3.org/2000/svg" class="m-skeleton-image-svg"><path class="u-skeleton-image-path" d="M365.714286 329.142857q0 45.714286-32.036571 77.677714t-77.677714 32.036571-77.677714-32.036571-32.036571-77.677714 32.036571-77.677714 77.677714-32.036571 77.677714 32.036571 32.036571 77.677714zM950.857143 548.571429l0 256-804.571429 0 0-109.714286 182.857143-182.857143 91.428571 91.428571 292.571429-292.571429zM1005.714286 146.285714l-914.285714 0q-7.460571 0-12.873143 5.412571t-5.412571 12.873143l0 694.857143q0 7.460571 5.412571 12.873143t12.873143 5.412571l914.285714 0q7.460571 0 12.873143-5.412571t5.412571-12.873143l0-694.857143q0-7.460571-5.412571-12.873143t-12.873143-5.412571zM1097.142857 164.571429l0 694.857143q0 37.741714-26.843429 64.585143t-64.585143 26.843429l-914.285714 0q-37.741714 0-64.585143-26.843429t-26.843429-64.585143l0-694.857143q0-37.741714 26.843429-64.585143t64.585143-26.843429l914.285714 0q37.741714 0 64.585143 26.843429t26.843429 64.585143z"></path></svg></div><div class="m-skeleton-header" v-if="avatar"><span:class="['u-skeleton-avatar',{'u-avatar-sm': typeof avatar !== 'boolean' && avatar.size === 'small','u-avatar-lg': typeof avatar !== 'boolean' && avatar.size === 'large','u-avatar-square': typeof avatar !== 'boolean' && avatar.shape === 'square',}]"></span></div><template v-if="!button && !image && !input"><div class="m-skeleton-content"><h3 class="u-skeleton-title" :style="{ width: titleWidth }"></h3><ul class="u-skeleton-paragraph"><li v-for="n in paragraphRows" :key="n" :style="`width: ${paragraphWidth[(n as number) - 1]};`"></li></ul></div></template></div><slot v-else></slot>
</template>
<style lang="less" scoped>
.m-skeleton {display: table;width: 100%;.u-skeleton-button {display: inline-block;vertical-align: top;background: rgba(0, 0, 0, .06);border-radius: 4px;width: 64px;min-width: 64px;height: 32px;line-height: 32px;}.u-button-sm {width: 48px;min-width: 48px;height: 24px;line-height: 24px;}.u-button-lg {width: 80px;min-width: 80px;height: 40px;line-height: 40px;}.u-button-round {border-radius: var(--button-size);}.u-button-circle {width: var(--button-size);min-width: var(--button-size);border-radius: 50%;}.u-button-block {width: 100%;}.u-skeleton-input {display: inline-block;vertical-align: top;background: rgba(0, 0, 0, 0.06);border-radius: 4px;width: 160px;min-width: 160px;height: 32px;line-height: 32px;}.u-input-sm {width: 120px;min-width: 120px;height: 24px;line-height: 24px;}.u-input-lg {width: 200px;min-width: 200px;height: 40px;line-height: 40px;}.m-skeleton-image {display: flex;align-items: center;justify-content: center;vertical-align: top;background: rgba(0, 0, 0, .06);border-radius: 4px;width: 96px;height: 96px;line-height: 96px;.m-skeleton-image-svg {width: 48px;height: 48px;line-height: 48px;max-width: 192px;max-height: 192px;.u-skeleton-image-path {fill: #bfbfbf;}}}.m-skeleton-header {display: table-cell;padding-right: 16px;vertical-align: top;.u-skeleton-avatar {display: inline-block;vertical-align: top;background: rgba(0, 0, 0, .06);width: 32px;height: 32px;line-height: 32px;border-radius: 50%;}.u-avatar-sm {width: 24px;height: 24px;line-height: 24px;}.u-avatar-lg {width: 40px;height: 40px;line-height: 40px;}.u-avatar-square {border-radius: 6px;}}.m-skeleton-content {display: table-cell;width: 100%;vertical-align: top;.u-skeleton-title {margin: 0;height: 16px;background: rgba(0, 0, 0, .06);border-radius: 4px;}.u-skeleton-paragraph {margin-top: 24px;padding: 0;li {height: 16px;list-style: none;background: rgba(0, 0, 0, .06);border-radius: 4px;&:not(:first-child) {margin-top: 16px;}&:last-child {width: 61%;}}}}
}
.m-skeleton-avatar {.m-skeleton-content {.u-skeleton-title {margin-top: var(--title-top);}.u-skeleton-paragraph {margin-top: 28px;}}
}
.m-skeleton-animated {.u-skeleton-button,.u-skeleton-input,.m-skeleton-image,.m-skeleton-header .u-skeleton-avatar,.m-skeleton-content .u-skeleton-title,.m-skeleton-content .u-skeleton-paragraph li {position: relative;z-index: 0;overflow: hidden;background: transparent;&::after {position: absolute;top: 0;left: -150%;bottom: 0;right: -150%;background: linear-gradient(90deg, rgba(0, 0, 0, .06) 25%, rgba(0, 0, 0, .15) 37%, rgba(0, 0, 0, .06) 63%);animation-name: skeleton-loading;animation-duration: 1.4s;animation-timing-function: ease;animation-iteration-count: infinite;content: "";}@keyframes skeleton-loading {0% {transform: translateX(-37.5%);}100% {transform: translateX(37.5%);}}}
}
</style>

在要使用的页面引入

<script setup lang="ts">
import Skeleton from './Skeleton.vue'
import { ref } from 'vue'const loading = ref<boolean>(false)const showSkeleton = () => {loading.value = truesetTimeout(() => {loading.value = false}, 2000)
}
const animated = ref(false)
const block = ref(false)
const size = ref('default')
const buttonShape = ref('default')
const avatarShape = ref('circle')
const sizeOptions = ref([{label: 'Default',value: 'default'},{label: 'Large',value: 'large'},{label: 'Small',value: 'small'}
])
const buttonShapeOptions = ref([{label: 'Default',value: 'default'},{label: 'Round',value: 'round'},{label: 'Circle',value: 'circle'}
])
const avatarShapeOptions = ref([{label: 'Square',value: 'square'},{label: 'Circle',value: 'circle'}
])
</script>
<template><div><h1>{{ $route.name }} {{ $route.meta.title }}</h1><h2 class="mt30 mb10">基本使用</h2><Skeleton /><h2 class="mt30 mb10">复杂的组合</h2><Skeleton avatar :paragraph="{ rows: 4 }" /><h2 class="mt30 mb10">包含子组件</h2><Button :loading="loading" @click="showSkeleton">Show Skeleton</Button><br/><br/><Skeleton :loading="loading"><div><h4>Vue Amazing UI, a design language</h4><br/><p>We supply a series of design principles, practical patterns and high quality designresources, to help people create their product prototypes beautifully and efficiently.</p></div></Skeleton><h2 class="mt30 mb10">自定义标题和段落</h2><Skeleton avatar :title="{ width: '24%' }" :paragraph="{ rows: 4, width: ['48%', '72%', '96%', '60%'] }" /><h2 class="mt30 mb10">按钮 / 输入框 / 图像 / 头像</h2><Flex :gap="32"><Flex vertical :gap="12" width="50%"><Skeleton :animated="animated" :button="{ shape: buttonShape, size: size, block: block}" /><Skeleton style="width: 200px" :animated="animated" :input="{ size: size }" /><Skeleton :animated="animated" image /><Skeleton :avatar="{ shape: avatarShape, size: size }" :paragraph="{ rows: 2 }" /></Flex><Flex vertical :gap="36" width="50%"><Space :size="32"><Space align="center">animated: <Switch v-model:checked="animated" /></Space><Space align="center">Button Block: <Switch v-model:checked="block" /></Space></Space><Space align="center">Size: <Radio :options="sizeOptions" v-model:value="size" /></Space><Space align="center">Button Shape: <Radio :options="buttonShapeOptions" v-model:value="buttonShape" /></Space><Space align="center">Avatar Shape: <Radio :options="avatarShapeOptions" v-model:value="avatarShape" /></Space></Flex></Flex></div>
</template>

相关文章:

Vue3骨架屏(Skeleton)

效果如下图&#xff1a;在线预览 APIs 参数说明类型默认值必传animated是否展示动画效果booleantruefalsebutton是否使用按钮占位图boolean | SkeletonButtonPropsfalsefalseavatar是否显示头像占位图boolean | SkeletonAvatarPropsfalsefalseinput是否使用输入框占位图boolea…...

【文末附gpt升级方案】亚马逊与Hugging Face合作:定制芯片低成本运行AI模型的创新探索

亚马逊与Hugging Face合作&#xff1a;定制芯片低成本运行AI模型的创新探索 摘要 本文探讨了亚马逊云部门与人工智能初创公司Hugging Face的合作&#xff0c;旨在通过定制计算芯片Inferentia2在亚马逊网络服务&#xff08;AWS&#xff09;上更低成本地运行数千个AI模型。文章首…...

二叉树的链式实现

目录 一、二叉树的基础操作 二、二叉树代码图解 2.1 遍历 2.2 求大小 2.3 创建与销毁 2.4 与队列结合解决问题 三、二叉树C语言源码汇总 二叉树的代码实现运用了函数递归的思想&#xff0c;了解函数递归的知识请见博主的另一篇博客&#xff1a; http://t.csdnimg.cn/Po…...

STM32中断编程入门

文章目录 一、 理论部分1.中断系统2.中断执行流程3.NVIC的基本结构4.EXTI介绍5.AFIO复用IO口 二、实验目的&#xff1a;学习stm32中断原理和开发编程方法。使用标准完成以下任务&#xff1a;&#xff08;一&#xff09;实验一 开关控制LED的亮灭1.代码部分2.运行结果 &#xff…...

《我的阿勒泰》读后感

暂没时间写&#xff0c;记录在此&#xff0c;防止忘记&#xff0c;后面补上!!! 【经典语录】 01、如果天气好的话&#xff0c;阳光广阔地照耀着世界&#xff0c;暖洋洋又懒洋洋。这样的阳光下&#xff0c;似乎脚下的每一株草都和我一样&#xff0c;也把身子完全舒展开了。 02、…...

Android.mk简单介绍、规则与基本格式

文章目录 Android.mk与makefile区别Android.mk规则Android.mk基本格式 Android.mk与makefile区别 Android.mk 和 Makefile 都是用于构建代码项目的构建脚本文件&#xff0c;但是它们在特定上下文中有一些区别&#xff1a; Android.mk: Android.mk 是用于构建 Android 应用或库…...

【MySQL精通之路】InnoDB(3)-MVCC多版本管理

InnoDB是一个多版本&#xff08;MVCC&#xff09;的存储引擎。 它保留有关更改行的旧版本的信息&#xff0c;以支持事务性功能&#xff0c;如并发和回滚。 这些信息存储在称为回滚段的数据结构中的Undo表空间中。 参见“Undo表空间”。 InnoDB使用回滚段&#xff08;rollback…...

uniapp 对接 微信App/支付宝App 支付

相关文档&#xff1a;uni.requestPayment(OBJECT) | uni-app官网 示例代码&#xff1a; import qs from qsasync aliPay(){const { provider } await uni.getProvider({ service:payment })if(provider.includes(alipay)){uni.request({url:后端接口地址,data:{ //传参 },suc…...

cmake配置opencv与boost库

Cmake配置外部依赖库&#xff08;以Opencv和Boost为例&#xff09; Cmake对于外部依赖库&#xff0c;需要知道外部库的头文件路径&#xff0c;库文件路径以及库的名字。比如&#xff0c;对于要使用的Boost库&#xff0c;需要知道头文件的位置&#xff0c;库目录的位置以及库依…...

【Kotlin 一】Kotlin入门知识简介、变量声明、数字类型

1. Kotlin简介 Kotlin旨在解决 Java语言在编码效率和代码质量上存在的问题&#xff0c;并且与Java语言完全兼容。Kotlin通过简化语法、提供更强大的函数以及减少样本代码的编写&#xff0c;使开发者能够更高效地编写代码。Kotlin适用于Android、Web后端开发等多种场景 2.Kotl…...

Java 微信小程序登录(openId方式)

1 需求 在开发微信小程序项目时&#xff0c;登录采用的是openId方式&#xff0c;这是一种用户无感的登录方式&#xff0c;用户点开微信小程序时&#xff0c;去调用后端的登录接口。 核心代码 Slf4j Component public class WeChatUtil {private static final String …...

为何程序员35岁就开始被嫌弃了?程序员该如何避免中年危机?

文章目录 一、为何程序员35岁就开始被嫌弃了&#xff1f;1、技术更新迅速2、职业发展瓶颈3、成本考虑4、年龄歧视5、市场供需变化6、个人因素 二、程序员该如何避免中年危机&#xff1f;1、持续学习与技能更新2、拓展技术广度与深度3、提升软技能4、关注行业趋势与市场变化5、建…...

【2024软考】史上最全!软考刷题+解析大合集(9万字全手工打,货真价实)

计算机基础知识 1.中断向量表用来保存各个中断源的中断服务程序的入口地址。当外设发出中断请求信号&#xff08;INTR&#xff09;以后&#xff0c;由中断控制器&#xff08;INTC&#xff09;确定其中断号&#xff0c;并根据中断号查找中断向量表来取得其中断服务程序的入口地…...

【Spring Security + OAuth2】授权

Spring Security OAuth2 第一章 Spring Security 快速入门 第二章 Spring Security 自定义配置 第三章 Spring Security 前后端分离配置 第四章 Spring Security 身份认证 第五章 Spring Security 授权 第六章 OAuth2 文章目录 Spring Security OAuth21、基于request的授权1…...

失落的方舟台服预下载教程 一键下载+账号注册教程

失落的方舟台服预下载教程 一键下载&#xff0b;账号注册教程 是一款今年备受瞩目的游戏&#xff0c;将于5月30日正式上线&#xff0c;这款游戏搭建在虚幻引擎的基础上&#xff0c;为玩家们带来了极佳的视觉体验。这款游戏秉承着MMO类型游戏一贯的玩法&#xff0c;但是制作组在…...

【启明智显技术分享】SOM2D02-2GW核心板适配ALSA(适用Sigmastar ssd201/202D)

提示&#xff1a;作为Espressif&#xff08;乐鑫科技&#xff09;大中华区合作伙伴及sigmastar&#xff08;厦门星宸&#xff09;VAD合作伙伴&#xff0c;我们不仅用心整理了你在开发过程中可能会遇到的问题以及快速上手的简明教程供开发小伙伴参考。同时也用心整理了乐鑫及星宸…...

人工智能的发展现状,AI将如何改变IT行业,哪些职业将最先失业

文章目录 一、人工智能的发展现状1、技术进展与突破2、商业应用与市场3、挑战与问题4、未来趋势 二、AI将如何改变IT行业1、工作方式的转变&#xff1a;2、未来发展的推动&#xff1a;3、用户服务和体验的提升&#xff1a;4、创新和转型的推动&#xff1a;5、融入日常生活和工作…...

request.js使用Promise.all等待所有请求完成再进行数据赋值

在JavaScript中&#xff0c;使用request.js发送多个并发请求&#xff0c;并使用Promise.all来处理这些请求的结果可以通过以下方式实现&#xff1a; 首先&#xff0c;确保你已经安装了request.js&#xff0c;如果没有&#xff0c;可以通过npm安装&#xff1a; npm install re…...

Java开发者必知的时间处理工具:SimpleDateFormat类详解

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…...

构造函数的用法

c 子类构造函数初始化及父类构造初始化_构造函数对父类进行初始化-CSDN博客...

美团外卖mtgsig与waimai_sign双层签名逆向解析

1. 这不是“爬虫教程”&#xff0c;而是一份反向工程现场笔记你搜到这篇内容&#xff0c;大概率正卡在某个调试窗口前&#xff1a;抓包看到mtgsig和waimai_sign两个参数像两堵墙&#xff0c;无论怎么改请求头、换UA、清缓存&#xff0c;返回永远是{"code":403,"…...

WarcraftHelper:魔兽争霸III现代兼容性问题的终极解决方案指南

WarcraftHelper&#xff1a;魔兽争霸III现代兼容性问题的终极解决方案指南 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 魔兽争霸III作为经典即时战…...

开源 AI Agent Harness Engineering 框架全览:LangChain, AutoGPT, CrewAI 孰优孰劣?

开源 AI Agent Harness Engineering 框架全览:LangChain, AutoGPT, CrewAI 孰优孰劣? 关键词 AI Agent Harness Engineering、大语言模型编排(LLM Orchestration)、LangChain、AutoGPT、CrewAI、工具调用(Tool Calling)、多Agent协作、自主任务规划 摘要 随着大语言模型…...

深度解析网络设备权限管理工具:中兴光猫工厂模式与Telnet服务完整指南

深度解析网络设备权限管理工具&#xff1a;中兴光猫工厂模式与Telnet服务完整指南 【免费下载链接】zteOnu A tool that can open ZTE onu device factory mode 项目地址: https://gitcode.com/gh_mirrors/zt/zteOnu 在当今网络设备管理领域&#xff0c;获取设备完整控制…...

深度解析HS2-HF Patch:从技术框架到创作工具链的完整升级方案

深度解析HS2-HF Patch&#xff1a;从技术框架到创作工具链的完整升级方案 【免费下载链接】HS2-HF_Patch Automatically translate, uncensor and update HoneySelect2! 项目地址: https://gitcode.com/gh_mirrors/hs/HS2-HF_Patch 你是否曾因Honey Select 2的原版体验受…...

InVideo插件深度解析:如何在Unreal Engine中实现高效视频流播放与录制

InVideo插件深度解析&#xff1a;如何在Unreal Engine中实现高效视频流播放与录制 【免费下载链接】InVideo 基于UE4实现的rtsp的视频播放插件 项目地址: https://gitcode.com/gh_mirrors/in/InVideo InVideo是一个基于Unreal Engine 5开发的RTSP视频播放插件&#xff0…...

DeepSeek模型微调全链路解析:从数据准备、LoRA配置到推理部署的7大关键步骤

更多请点击&#xff1a; https://intelliparadigm.com 第一章&#xff1a;DeepSeek模型微调全链路概览 DeepSeek系列大语言模型&#xff08;如DeepSeek-V2、DeepSeek-Coder&#xff09;凭借其开源特性、高性能推理能力与丰富的领域适配性&#xff0c;已成为工业界与学术界微调…...

Style-Bert-VITS2未来发展方向:从语音克隆到实时语音转换的技术演进路线

Style-Bert-VITS2未来发展方向&#xff1a;从语音克隆到实时语音转换的技术演进路线 【免费下载链接】Style-Bert-VITS2 Style-Bert-VITS2: Bert-VITS2 with more controllable voice styles. 项目地址: https://gitcode.com/gh_mirrors/st/Style-Bert-VITS2 Style-Bert…...

大厂校招变了:AI 能力正在进入笔试和面试

最近不少同学投递校招时&#xff0c;应该已经发现一个变化&#xff1a; 以前 JD 里写的是“熟悉 Python / Java / SQL / Office 优先”。 现在越来越多岗位开始出现新的描述&#xff1a; “熟练使用 AI 工具者优先” “了解大模型应用者优先” “具备 AI 辅助编程经验优先” “…...

3步终结Windows热键冲突:Hotkey Detective终极排查指南

3步终结Windows热键冲突&#xff1a;Hotkey Detective终极排查指南 【免费下载链接】hotkey-detective A small program for investigating stolen key combinations under Windows 7 and later. 项目地址: https://gitcode.com/gh_mirrors/ho/hotkey-detective 你是否曾…...