Shadcn UI 实战:打造可维护的企业级组件库
"我们真的需要自己写一套组件库吗?"上周的技术评审会上,我正在和团队讨论组件库的选型。作为一个快速发展的创业公司,我们既需要高质量的组件,又想保持灵活的定制能力。在对比了多个方案后,我们选择了 shadcn/ui 这个相对较新的解决方案。
说实话,最开始我对这个决定也有些担忧。毕竟相比 Ant Design 这样的成熟方案,shadcn/ui 的知名度确实不高。但经过一个月的实践,这个选择让我们收获了意外的惊喜。
为什么选择 shadcn/ui?
传统组件库给我们带来了一些困扰:
- 样式难以深度定制
- 打包体积大
- 版本升级困难
- 组件逻辑难以调整
就像租房和买房的选择一样,使用第三方组件库就像租房,虽然能快速入住,但想改造却处处受限。而 shadcn/ui 的方案,更像是买了一栋毛坯房,虽然需要自己装修,但能完全掌控每个细节。
项目实践
1. 初始化配置
首先,我们需要建立一个良好的组件开发基础:
// components.json
{"$schema": "https://ui.shadcn.com/schema.json","style": "default","rsc": true,"tailwind": {"config": "tailwind.config.js","css": "app/globals.css","baseColor": "slate","cssVariables": true},"aliases": {"components": "@/components","utils": "@/lib/utils"}
}// tailwind.config.js
const { fontFamily } = require('tailwindcss/defaultTheme')/** @type {import('tailwindcss').Config} */
module.exports = {darkMode: ['class'],content: ['app/**/*.{ts,tsx}', 'components/**/*.{ts,tsx}'],theme: {container: {center: true,padding: '2rem',screens: {'2xl': '1400px'}},extend: {colors: {border: 'hsl(var(--border))',input: 'hsl(var(--input))',ring: 'hsl(var(--ring))',background: 'hsl(var(--background))',foreground: 'hsl(var(--foreground))',primary: {DEFAULT: 'hsl(var(--primary))',foreground: 'hsl(var(--primary-foreground))'}},borderRadius: {lg: 'var(--radius)',md: 'calc(var(--radius) - 2px)',sm: 'calc(var(--radius) - 4px)'},fontFamily: {sans: ['var(--font-sans)', ...fontFamily.sans]}}}
}
2. 组件定制
shadcn/ui 最大的特点是它的组件是可以复制到项目中的。这让我们能够根据业务需求进行深度定制:
// components/ui/button.tsx
import * as React from 'react'
import { Slot } from '@radix-ui/react-slot'
import { cva, type VariantProps } from 'class-variance-authority'
import { cn } from '@/lib/utils'// 扩展按钮变体
const buttonVariants = cva('inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50', {variants: {variant: {default: 'bg-primary text-primary-foreground hover:bg-primary/90',destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',outline: 'border border-input hover:bg-accent hover:text-accent-foreground',secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',ghost: 'hover:bg-accent hover:text-accent-foreground',link: 'underline-offset-4 hover:underline text-primary',// 添加自定义变体brand: 'bg-brand-500 text-white hover:bg-brand-600',success: 'bg-green-500 text-white hover:bg-green-600'},size: {default: 'h-10 px-4 py-2',sm: 'h-9 rounded-md px-3',lg: 'h-11 rounded-md px-8',icon: 'h-10 w-10'}},defaultVariants: {variant: 'default',size: 'default'}
})// 扩展按钮属性
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {asChild?: booleanloading?: booleanicon?: React.ReactNode
}const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(({ className, variant, size, asChild = false, loading, icon, children, ...props }, ref) => {const Comp = asChild ? Slot : 'button'return (<Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props}>{loading && <LoadingSpinner className='mr-2 h-4 w-4 animate-spin' />}{icon && <span className='mr-2'>{icon}</span>}{children}</Comp>)
})
Button.displayName = 'Button'
3. 主题定制
我们实现了一个灵活的主题切换系统:
// lib/themes.ts
export const themes = {light: {'--background': '0 0% 100%','--foreground': '222.2 84% 4.9%','--primary': '222.2 47.4% 11.2%','--primary-foreground': '210 40% 98%'// ... 其他颜色变量},dark: {'--background': '222.2 84% 4.9%','--foreground': '210 40% 98%','--primary': '210 40% 98%','--primary-foreground': '222.2 47.4% 11.2%'// ... 其他颜色变量},// 添加自定义主题brand: {'--background': '0 0% 100%','--foreground': '222.2 84% 4.9%','--primary': '220 90% 56%','--primary-foreground': '210 40% 98%'}
}// components/theme-provider.tsx
const ThemeProvider = ({ children }: { children: React.ReactNode }) => {const [theme, setTheme] = useState('light')useEffect(() => {const root = document.documentElementconst themeVars = themes[theme as keyof typeof themes]Object.entries(themeVars).forEach(([key, value]) => {root.style.setProperty(key, value)})}, [theme])return <ThemeContext.Provider value={{ theme, setTheme }}>{children}</ThemeContext.Provider>
}
4. 组件封装
基于 shadcn/ui 的基础组件,我们封装了一些业务组件:
// components/business/data-table.tsx
import { Table } from '@/components/ui/table'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { useState } from 'react'interface DataTableProps<T> {data: T[]columns: Column[]onEdit?: (record: T) => voidonDelete?: (record: T) => void
}export function DataTable<T>({ data, columns, onEdit, onDelete }: DataTableProps<T>) {const [searchText, setSearchText] = useState('')const filteredData = data.filter(record =>columns.some(column => {const value = record[column.key as keyof T]return String(value).toLowerCase().includes(searchText.toLowerCase())}))return (<div className='space-y-4'><div className='flex justify-between'><Input placeholder='搜索...' value={searchText} onChange={e => setSearchText(e.target.value)} className='max-w-sm' /></div><Table><Table.Header>{columns.map(column => (<Table.Column key={column.key}>{column.title}</Table.Column>))}<Table.Column>操作</Table.Column></Table.Header><Table.Body>{filteredData.map((record, index) => (<Table.Row key={index}>{columns.map(column => (<Table.Cell key={column.key}>{record[column.key as keyof T]}</Table.Cell>))}<Table.Cell><div className='space-x-2'>{onEdit && (<Button size='sm' variant='outline' onClick={() => onEdit(record)}>编辑</Button>)}{onDelete && (<Button size='sm' variant='destructive' onClick={() => onDelete(record)}>删除</Button>)}</div></Table.Cell></Table.Row>))}</Table.Body></Table></div>)
}
实践效果
经过一个月的使用,我们获得了显著的收益:
- 打包体积减少了 60%
- 组件定制更加灵活
- 开发效率提升
- 代码可维护性增强
最让我印象深刻的是一位同事说:"终于可以随心所欲地修改组件了,不用再为覆盖第三方样式发愁。"
经验总结
使用 shadcn/ui 的过程让我们学到:
- 组件库不一定要追求"拿来即用"
- 掌控组件源码比黑盒封装更有优势
- 样式系统的一致性很重要
- 渐进式地构建组件库是个好方法
就像装修房子,虽然前期投入较大,但最终得到的是一个完全符合需求的解决方案。
写在最后
shadcn/ui 给了我们一个全新的视角:组件库可以是一系列最佳实践的集合,而不仅仅是一个封装好的产品。正如那句话说的:"授人以鱼不如授人以渔",shadcn/ui 不仅给了我们组件,更教会了我们如何构建组件。
有什么问题欢迎在评论区讨论,让我们一起探讨组件库开发的更多可能!
如果觉得有帮助,别忘了点赞关注,我会继续分享更多实战经验~
相关文章:
Shadcn UI 实战:打造可维护的企业级组件库
"我们真的需要自己写一套组件库吗?"上周的技术评审会上,我正在和团队讨论组件库的选型。作为一个快速发展的创业公司,我们既需要高质量的组件,又想保持灵活的定制能力。在对比了多个方案后,我们选择了 shadcn/ui 这个相对较新的解决方案。 说实话,最开始…...
C#速成(GID+图形编程)
常用类 类说明Brush填充图形形状,画刷GraphicsGDI绘图画面,无法继承Pen定义绘制的对象直线等(颜色,粗细)Font定义文本格式(字体,字号) 常用结构 结构说明Color颜色Point在平面中定义点Rectan…...
CMD使用SSH登陆Ubuntu
1.确认sshserver是否安装好 ps -e | grep sshd 450 ? 00:00:00 sshd 2、如果看到sshd那说明ssh-server已经启动了 其实在/etc/ssh下有一个sshd_config 文件。对这个文件进行修改vim sshd_config。 往文件中添加如下内容: Port 22 Protocol 2 PermitRootLogin yes P…...
Fay环境安装及使用
一、项目源码 代码地址 : Fay 2D数字人源码地址:xuniren LLM用是清华开源的ChatGLM源码地址:ChatGLM-6B 模型地址chatglm2-6b-int4 (大模型的安装直接参考了我的另一篇文章:ChatGLM2-6B-int4的…...
重写 `equals` 和 `hashCode` 的一致性
重写 equals 和 hashCode 的一致性 在 Java 中,当我们重写 equals 方法时,通常需要同时重写 hashCode 方法,以确保对象在逻辑上相等时,其哈希值也相等。这是一种重要的契约(contract),主要用于…...
【游戏设计原理】14 - MDA:游戏的机制、运行和体验
1. 学习、分析并总结 MDA 原理 MDA (Mechanics, Dynamics, and Aesthetics) 是一种用来分析和理解游戏设计的框架,由 Marc LeBlanc, Robin Hunicke, 和 Robert Zubek 提出。这个框架将游戏分解为三个核心要素: Mechanics(机制)&…...
鸿蒙Next创建自定义组件总结
一、引言 在鸿蒙Next开发中,自定义组件是构建高效、可维护UI的重要组成部分。它具有可组合、可重用以及数据驱动UI更新等特点,能帮助开发者更好地实现代码复用、业务逻辑与UI分离等目标。本文将详细总结创建自定义组件的相关知识,包括其基本…...
redis 缓存使用
工具类 package org.springblade.questionnaire.redis;import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.beans.factor…...
Javascript面试手撕常见题目(回顾一)
1.JS查找文章中出现频率最高的单词? 要在JavaScript中查找文章中出现频率最高的单词,你可以按照以下步骤进行操作: 将文章转换为小写:这可以确保单词的比较是大小写不敏感的。移除标点符号:标点符号会干扰单词的计数。将文章拆…...
lc146LRU缓存——模仿LinkedHashMap
146. LRU 缓存 - 力扣(LeetCode) 法1: 调用java现有的LinkedHashMap的方法,但不太理解反正都不需要扩容,super(capacity, 1F, true);不行吗,干嘛还弄个装载因子0.75还中途扩容一次浪费时间。 class LRUC…...
【C语言】头文件
所有学习过C语言的朋友都熟悉这样一段代码: #include <stdio.h>int main(int argc, char *argv[]) {return 0; }那么,你真的了解 <stdio.h> 吗? <stdio…...
WSL (Windows Subsystem for Linux)
文章目录 Windows下使用Linux的三种方式:1.WSL(1)安装WSL(2)初始化Linux系统(3)安装、创建、激活 Python虚拟环境 2.虚拟机3.Docker Windows下使用Linux的三种方式: 1.WSL 是最简单的在 Windows 上运行 Linux 环境的方式,适用于日常开发和命…...
[Java] 使用 VSCode 来开发 Java
目录 前言Java 环境怎么看自己是否已经配置完成?安装 JDK安装 Maven 环境修改 Maven 依赖源 完善 VS Code配置插件配置 Maven配置 Maven Settings配置 Maven 可执行文件地址 前言 由于使用 VSCode 编码已经成为习惯,并且它确实相对其他的 IDE 较为轻量化…...
机器学习之偏差
机器学习中的偏差(Bias)是指模型的预测值与真实值之间的系统性误差,或者说模型无法准确捕捉数据中复杂模式的能力。偏差通常与模型的假设或学习能力有关,过高的偏差会导致模型的性能不佳,表现为欠拟合。 偏差的来源 模…...
微信小程序处理交易投诉管理,支持多小程序
大家好,我是小悟 1、问题背景 玩过微信小程序生态的,或许就有这种感受,如果收到投诉单,不会及时通知到手机端,而是每天早上10:00向小程序的管理员及运营者推送通知。通知内容为截至前一天24时该小程序账号内待处理的交…...
在C#中测试比较目录的不同方法以查看它们有哪些共同的文件
C# 中的示例“比较目录以查看它们有哪些共同的文件”使用Directory.GetFiles获取两个目录中的文件。它对文件进行排序,并比较两个排序后的列表以查看哪些文件位于第一个目录中、第二个目录中或两个目录中。有关其工作原理的详细信息,请参阅该示例。 Kur…...
2D gaussian splatting的配置和可视化
继3D gaussian splatting,2D gaussian splatting除了渲染新视角,还能够生成mesh模型。 2D gaussian splatting的配置 两者的运行环境基本一致 GitHub - hbb1/2d-gaussian-splatting: [SIGGRAPH24] 2D Gaussian Splatting for Geometrically Accurate …...
git分支管理
目录 1.Git分支管理1.1 分支创建1.2 分支删除1.3 分支合并1.4 分支的本质1.5 分支的冲突 2.Git stash2.1 git stash 3.分支管理策略3.1主分支3.2辅助分支3.3Feature分支3.4release分支3.5bugfix分支 1.Git分支管理 Git 的默认分支就是 master。你所作的commit会在master分支上…...
【Elasticsearch入门到落地】4、Elasticsearch的安装
接上篇《3、es与mysql的概念对比》 上一篇我们学习了Elasticsearch与Mysql的概念与区别。本篇我们来进行Elasticsearch的环境准备及软件安装。 一、环境准备 如果我们没有自己的Linux服务器,且现在正在使用的是Windows操作系统的电脑,那么首先我们需要安…...
如何在谷歌浏览器中开启安全浏览
在数字化时代,网络安全变得愈发重要。作为全球最受欢迎的网络浏览器之一,谷歌浏览器提供了多种功能来保护用户的在线安全。本文将详细介绍如何在谷歌浏览器中开启安全浏览,并额外提供一些有用的页面滚动设置、地址栏快捷搜索和跟踪防护的相关…...
短视频矩阵贴牌:打造品牌新势力的策略与实践
在数字化浪潮席卷全球的今天,短视频以其独特的魅力迅速崛起,成为连接用户与品牌的重要桥梁。企业为了快速抢占市场,提升品牌影响力,纷纷探索短视频矩阵贴牌这一新兴模式。本文将深入探讨短视频矩阵贴牌的概念、优势、实施流程及注…...
【潜意识Java】javaee中的SpringBoot在Java 开发中的应用与详细分析
目录 一、前言 二、Spring Boot 简介 三、Spring Boot 核心模块 四、Spring Boot 项目实战:构建一个简单的 RESTful API 1. 创建 Spring Boot 项目 2. 配置数据库 3. 创建实体类 4. 创建 JPA 仓库接口 5. 创建服务层 6. 创建控制器层 7. 测试 API 8. 运…...
linux basics
本篇文章旨在为网络安全初学者介绍linux操作系统基础。通过阅读本文,读者将能够对linux系统有一个初步的了解 一、openssl 1、命令: openssl passwd -1 123 -l参数指定使用MD5加密算法对密码"123"进行加密处理。MD5是一种常用的哈希算法,它将…...
[OpenGL] Transform feedback 介绍以及使用示例
一、简介 本文介绍了 OpenGL 中 Transform Feedback 方法的基本概念和代码示例。 二、Transform Feedback 介绍 1. Transform Feedback 简介 根据 OpenGL-wiki,Transform Feedback 是捕获由顶点处理步骤(vertex shader 和 geometry shader࿰…...
pytorch_fid 安装笔记
目录 torch安装: pytorch_fid安装 torch安装: pip install torch2.5.0 --index-url https://download.pytorch.org/whl/cu121 pytorch_fid安装 pip install pytorch_fid 安装后,torch也会自动安装,导致torch引用报错。...
SAM大模型实践(一)
参考着segment-geospatial 项目主页的介绍,尝试复现一下Example-satallite的案例。 Satellite - segment-geospatialhttps://samgeo.gishub.org/examples/satellite/ 过程当中遇到了一些坑给大家做点分享,主要有几种情况,一个是torch…...
数据结构 ——前缀树查词典的实现
数据结构 ——前缀树查词典的实现 一、前缀树的概念 前缀树是一种多叉树结构,主要用于存储字符串。每个节点代表一个字符,路径从根节点到叶节点表示一个完整的字符串。前缀树的关键特征是 共享前缀,也就是说,如果两个字符串有相…...
边缘智能创新应用大赛获奖作品系列一:智能边缘计算✖软硬件一体化,开启全场景效能革命新征程
边缘智能技术快速迭代,并与行业深度融合。它正重塑产业格局,催生新产品、新体验,带动终端需求增长。为促进边缘智能技术的进步与发展,拓展开发者的思路与能力,挖掘边缘智能应用的创新与潜能,高通技术公司联…...
修改ubuntu apt 源及apt 使用
视频教程:修改ubuntu apt 源和apt 使用方法_哔哩哔哩_bilibili 1 修改apt源 1.1 获取阿里云ubuntu apt 源 https://developer.aliyun.com/mirror/ubuntu?spma2c6h.13651102.0.0.3e221b11mqqLBC 1.2 修改apt 源 vim /etc/apt/sources.list deb https://mirrors.aliyun.com/ub…...
Kafka 磁道寻址过程详解
前言 Apache Kafka 是一款高吞吐、分布式的消息流平台,广泛应用于实时数据处理和事件驱动系统。在 Kafka 中,消息是存储在磁盘上的,这种高效的数据读写性能得益于 Kafka 独特的磁盘存储架构和寻址机制。本文将从 Kafka 的存储结构、磁道寻址…...
GEE+本地XGboot分类
GEE本地XGboot分类 我想做提取耕地提取,想到了一篇董金玮老师的一篇论文,这个论文是先提取的耕地,再做作物分类,耕地的提取代码是开源的。 但这个代码直接在云端上进行分类,GEE会爆内存,因此我准备把数据下…...
安防监控Liveweb视频汇聚融合平台助力执法记录仪高效使用
Liveweb平台可接入的设备除了常见的智能分析网关与摄像头以外 ,还可通过GB28181协议接入执法记录仪,实现对执法过程的全程监控与录像,并对执法轨迹与路径进行调阅回看。那么,如何做到执法记录仪高效使用呢? 由于执法记…...
酷盾安全:Edge SCDN边缘安全内容分发网络
在当今数字化迅猛发展的时代,互联网内容分发的高效与安全成为了企业不可忽视的重要课题。为了满足这一需求,酷盾安全推出了创新的Edge Secure Content Delivery Network(Edge Scdn)解决方案,它不仅融合了分布式DDoS防护…...
决策引擎技术
决策引擎(Decision Engine)是一种用于自动化决策过程的软件系统。它通常用于处理复杂的业务逻辑,根据输入的数据和预定义的规则或模型来做出决策。决策引擎在许多领域都有广泛的应用,如金融、保险、医疗、供应链管理等。 在Java中…...
Servlet学习中遇到的一些问题及解决
错误:JavaWeb-错误:类xxx不是Servlet 解决:可能是Tomcat版本不匹配导致,更换Tomcat版本解决问题 错误:在自定义的Servlet类中不能添加 WebServlet 注解 解决:可能是WebServlet版本不匹配,更换…...
oracle开窗函数笔记、over()笔记
文章目录 开窗函数、组函数、分析函数概念聚合函数和分析函数的区别partition by后面也可以跟多个字段 开窗函数一定要加 聚合函数、或分析函数吗,否则会报错lag()和lead()的用法lag和lead实战开窗函数可以和其他函数一起使用吗? TODO开窗函数中的count(1)是什么意…...
深度学习面试相关-2024.12.15记录
深度学习 面试相关- 2024.12.15记录 目录 深度学习 面试相关- 2024.12.15记录整体常问问题1数学基础1.1 概率统计1.2 线代 2机器学习算法2.1 深度学习算法2.2 机器学习算法 整体常问问题 https://www.nowcoder.com/discuss/353154899112304640 1数学基础 1.1 概率统计 htt…...
CSS|07 标准文档流
标准文档流 一、什么是标准文档流 在制作的 HTML 网页和 PS 画图软件画图时有本质上面的区别: HTML 网页在制作的时候都得遵循一个“流的规则:从左至右、从上至下。 使用 Ps 软件画图时可以在任意地方画图。 <!DOCTYPE html> <html lang"en"> <hea…...
1 JVM JDK JRE之间的区别以及使用字节码的好处
JDK jdk是编译java源文件成class文件的,我们使用javac命令把java源文件编译成class文件。 我们在java安装的目录下找到bin文件夹,如下图所示: 遵循着编译原理,把java源文件编译成JVM可识别的机器码。 其中还包括jar打包工具等。主要是针对…...
ubuntu安装8812au驱动却无法加载网卡的问题
驱动GIT地址 https://github.com/aircrack-ng/rtl8812au按照里面提示安装驱动 输入 sudo dkms status查看驱动是否安装成功 接入网卡,看看ifconfig能否输出网卡 如果不行 使用sudo dmesg -w插拔网卡看看输出 如果输出为: load module with unavailable key is …...
Eureka学习笔记-服务端
Eureka学习笔记 服务端 模块设计 Resources :这部分对外暴露了一系列的 Restful 接口。Eureka Client 的注册、心跳、获取服务列表等操作都需要调用这些接口。另外,其他的 Server 在同步 Registry 时也需要调用这些接口。Controller :这里提…...
LangChain
文章目录 一、LangChain 是什么?二、核心概念1. LLM Wrappers2. Prompt Templates3. Indexes4. Chains5. Agents 三、工作流程四、应用场景示例一:简单的语言模型调用示例二:使用Prompt Templates(提示模板)示例三&…...
搭建分布式Hive集群
title: 搭建分布式Hive集群 date: 2024-11-29 23:39:00 categories: - 服务器 tags: - Hive - 大数据搭建分布式Hive集群 本次实验环境:Centos 7-2009、Hadoop-3.1.4、JDK 8、Zookeeper-3.6.3、Mysql-5.7.38、Hive-3.1.2 功能规划 方案一(本地运行模…...
Scala的惰性求值:深入理解与实践
在编程中,我们经常需要处理那些计算成本高昂或者可能永远不会用到的值。在这种情况下,惰性求值(Lazy Evaluation)是一种非常有用的策略。它允许我们推迟计算,直到这些值真正需要被使用。Scala,作为一种多功…...
游戏引擎学习第54天
仓库: https://gitee.com/mrxiao_com/2d_game 回顾 我们现在正专注于在游戏世界中放置小实体来代表所有的墙。这些实体围绕着世界的每个边缘。我们有活跃的实体,这些实体位于玩家的视野中,频繁更新,而那些离玩家较远的实体则以较低的频率运…...
QT绘制同心扇形
void ChartForm::paintEvent(QPaintEvent *) {QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing);// 设置抗锯齿painter.save();// 设置无边框(不需要设置QPen,因为默认是不绘制边框的)QPen pen(Qt::NoPen);// QPen pen…...
梳理你的思路(从OOP到架构设计)_浅尝架构师的滋味02
目录 1、 App开发者的职责:买主提供需求知识,App开发者帮他写代码 撰写的代码 撰写代码,将装配(扩充)到 2、 从生活中体会 基於軟硬整合觀點“两种知识” 编辑 1、 App开发者的职责:买主提供需求知识,App开发者帮…...
使用VLC 搭建 RTSP 服务器
第一步:打开 VLC ,媒体--->流 第二步:添加一个选择本地的文件,然后点击选择"串流" 第三步:确认你选择的文件,然后点击下一个 第四步: 配置 选择的视频文件使用哪种 流输出…...
什么是大型语言模型
大型语言模型简介 大型语言模型 (LLM) 是一种深度学习算法,可以使用非常大的数据集识别、总结、翻译、预测和生成内容。 NVIDIA 开发者计划 想要了解有关 NIM 的更多信息?加入 NVIDIA 开发者计划,即可免费访问任何基础设施云、数据中心或个…...
游卡,科锐国际,蓝禾,汤臣倍健,顺丰,途游游戏25秋招内推
游卡,科锐国际,蓝禾,汤臣倍健,顺丰,途游游戏25秋招内推 ①科锐国际25届秋招补录 人力资源类岗位,补录城市:上海,苏州,锦州;全日制公办本科及以上 25届应届毕业…...