WHAT - 通过 shadcn 组件源码学习 React
目录
- 一、button
- 1. 导入部分
- 2. 定义按钮的样式变体
- 1. `variant`
- 2. `size`
- 总结
- 3. 定义按钮的属性类型
- 4. 定义按钮组件
- 5. 导出组件和样式变体
- 总结
- 二、multi-select
- 多选组件的核心上下文与状态
- 1. 上下文与钩子
- 2. MultiSelector 组件
- 组件子部分
- 1. MultiSelectorTrigger
- 2. MultiSelectorInput
- 3. MultiSelectorContent
- 4. MultiSelectorList
- 5. MultiSelectorItem
- 总结
一、button
组件来源:https://ui.shadcn.com/docs/components/button
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 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 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 bg-background hover:bg-accent hover:text-accent-foreground",secondary:"bg-secondary text-secondary-foreground hover:bg-secondary/80",disabled:"disabled-foreground bg-disabled text-disabled-foreground",ghost: "hover:bg-accent focus-visible:ring-0 focus-visible:ring-offset-0",link: "hover:text-primary underline-offset-4",icon: "border border-input",},size: {default: "h-8 px-5 py-1.5",sm: "h-9 rounded-md px-3",lg: "h-11 rounded-md px-8",icon: "h-6 w-6",iconSm: "h-8 w-8",ssm: "h-6",},},defaultVariants: {variant: "default",size: "default",},},
)export interface ButtonPropsextends React.ButtonHTMLAttributes<HTMLButtonElement>,VariantProps<typeof buttonVariants> {asChild?: boolean
}const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(({ className, variant, size, asChild = false, ...props }, ref) => {const Comp = asChild ? Slot : "button"return (<CompclassName={cn(buttonVariants({ variant, size, className }))}ref={ref}{...props}/>)},
)
Button.displayName = "Button"export { Button, buttonVariants }
这段代码定义了一个可变样式的按钮组件Button
,使用了多个工具和库。我们将逐步解释各部分代码的作用。
1. 导入部分
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"
React
: 导入React库。Slot
: 从@radix-ui/react-slot
库中导入Slot
组件,用于支持“asChild”属性。cva
和VariantProps
: 从class-variance-authority
库中导入,用于定义可变样式。cn
: 从项目中的utils
工具库导入cn
函数,用于合并CSS类名。
2. 定义按钮的样式变体
const buttonVariants = cva("inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 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 bg-background hover:bg-accent hover:text-accent-foreground",secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",disabled: "disabled-foreground bg-disabled text-disabled-foreground",ghost: "hover:bg-accent focus-visible:ring-0 focus-visible:ring-offset-0",link: "hover:text-primary underline-offset-4",icon: "border border-input",},size: {default: "h-8 px-5 py-1.5",sm: "h-9 rounded-md px-3",lg: "h-11 rounded-md px-8",icon: "h-6 w-6",iconSm: "h-8 w-8",ssm: "h-6",},},defaultVariants: {variant: "default",size: "default",},},
)
buttonVariants
: 使用cva
函数定义了按钮的样式变体。这个对象包含了两个主要部分:variants
: 定义了不同的变体选项,如variant
和size
,每个选项又包含不同的具体样式。defaultVariants
: 定义了默认的变体值。
当然,让我们逐一解释variants
对象中的每个属性及其对应的CSS属性值。
1. variant
variant
属性定义了按钮的多种视觉风格,每种风格都对应一组CSS类名。
-
default
bg-primary {background-color: var(--primary-color); } text-primary-foreground {color: var(--primary-foreground-color); } hover:bg-primary/90 {background-color: var(--primary-color);opacity: 0.9; }
-
destructive
bg-destructive {background-color: var(--destructive-color); } text-destructive-foreground {color: var(--destructive-foreground-color); } hover:bg-destructive/90 {background-color: var(--destructive-color);opacity: 0.9; }
-
outline
border border-input {border: 1px solid var(--input-border-color); } bg-background {background-color: var(--background-color); } hover:bg-accent {background-color: var(--accent-color); } hover:text-accent-foreground {color: var(--accent-foreground-color); }
-
secondary
bg-secondary {background-color: var(--secondary-color); } text-secondary-foreground {color: var(--secondary-foreground-color); } hover:bg-secondary/80 {background-color: var(--secondary-color);opacity: 0.8; }
-
disabled
disabled-foreground {color: var(--disabled-foreground-color); } bg-disabled {background-color: var(--disabled-color); } text-disabled-foreground {color: var(--disabled-foreground-color); }
-
ghost
hover:bg-accent {background-color: var(--accent-color); } focus-visible:ring-0 {outline: none;box-shadow: none; } focus-visible:ring-offset-0 {box-shadow: none; }
-
link
hover:text-primary {color: var(--primary-color); } underline-offset-4 {text-underline-offset: 4px; }
-
icon
border border-input {border: 1px solid var(--input-border-color); }
2. size
size
属性定义了按钮的不同尺寸,每个尺寸都对应一组CSS类名。
-
default
h-8 {height: 2rem; /* 32px */ } px-5 {padding-left: 1.25rem; /* 20px */padding-right: 1.25rem; /* 20px */ } py-1.5 {padding-top: 0.375rem; /* 6px */padding-bottom: 0.375rem; /* 6px */ }
-
sm
h-9 {height: 2.25rem; /* 36px */ } rounded-md {border-radius: 0.375rem; /* 6px */ } px-3 {padding-left: 0.75rem; /* 12px */padding-right: 0.75rem; /* 12px */ }
-
lg
h-11 {height: 2.75rem; /* 44px */ } rounded-md {border-radius: 0.375rem; /* 6px */ } px-8 {padding-left: 2rem; /* 32px */padding-right: 2rem; /* 32px */ }
-
icon
h-6 {height: 1.5rem; /* 24px */ } w-6 {width: 1.5rem; /* 24px */ }
-
iconSm
h-8 {height: 2rem; /* 32px */ } w-8 {width: 2rem; /* 32px */ }
-
ssm
h-6 {height: 1.5rem; /* 24px */ }
总结
这些variants
属性提供了丰富的样式变体,使得按钮组件可以根据不同的需求应用不同的外观和尺寸,通过简单的属性传递实现了多样化的视觉效果。
3. 定义按钮的属性类型
export interface ButtonPropsextends React.ButtonHTMLAttributes<HTMLButtonElement>,VariantProps<typeof buttonVariants> {asChild?: boolean
}
ButtonProps
: 定义了按钮组件的属性接口,扩展了React.ButtonHTMLAttributes
和VariantProps
。另外,还增加了asChild
属性,用于指定是否将按钮作为子组件渲染。
4. 定义按钮组件
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(({ className, variant, size, asChild = false, ...props }, ref) => {const Comp = asChild ? Slot : "button"return (<CompclassName={cn(buttonVariants({ variant, size, className }))}ref={ref}{...props}/>)},
)
Button.displayName = "Button"
Button
: 使用React.forwardRef
定义一个带有转发引用(ref)的按钮组件。Comp
: 根据asChild
属性,动态决定使用Slot
组件还是button
元素。cn(buttonVariants({ variant, size, className }))
: 使用cn
函数合并传入的className
和通过buttonVariants
生成的变体样式。
5. 导出组件和样式变体
export { Button, buttonVariants }
Button
和buttonVariants
均被导出,允许在其他模块中使用。
总结
这个组件使用了class-variance-authority
库来管理按钮的样式变体,通过React的forwardRef
和条件渲染实现了灵活的按钮组件。这样,开发者可以通过简单的属性传递来改变按钮的外观和行为。
二、multi-select
组件来源:https://shadcn-extension.vercel.app/docs/multi-select
如果希望有远程搜索能力,可以参考 https://shadcnui-expansions.typeart.cc/docs/multiple-selector
"use client";import { Badge } from "@/components/ui/badge";
import {Command,CommandItem,CommandEmpty,CommandList,
} from "@/components/ui/command";
import { cn } from "@/lib/utils";
import { Command as CommandPrimitive } from "cmdk";
import { X as RemoveIcon, Check } from "lucide-react";
import React, {KeyboardEvent,createContext,forwardRef,useCallback,useContext,useState,
} from "react";type MultiSelectorProps = {values: string[];onValuesChange: (value: string[]) => void;loop?: boolean;options: {label: string, value: string, color?: string}[];
} & React.ComponentPropsWithoutRef<typeof CommandPrimitive>;interface MultiSelectContextProps {value: string[];options: {label: string, value: string, color?: string}[];onValueChange: (value: any) => void;open: boolean;setOpen: (value: boolean) => void;inputValue: string;setInputValue: React.Dispatch<React.SetStateAction<string>>;activeIndex: number;setActiveIndex: React.Dispatch<React.SetStateAction<number>>;
}const MultiSelectContext = createContext<MultiSelectContextProps | null>(null);const useMultiSelect = () => {const context = useContext(MultiSelectContext);if (!context) {throw new Error("useMultiSelect must be used within MultiSelectProvider");}return context;
};const MultiSelector = ({values: value,onValuesChange: onValueChange,loop = false,className,children,dir,options,...props
}: MultiSelectorProps) => {const [inputValue, setInputValue] = useState("");const [open, setOpen] = useState<boolean>(false);const [activeIndex, setActiveIndex] = useState<number>(-1);const onValueChangeHandler = useCallback((val: string) => {if (value.includes(val)) {onValueChange(value.filter((item) => item !== val));} else {onValueChange([...value, val]);}},[value]);// TODO : change from else if use to switch case statementconst handleKeyDown = useCallback((e: KeyboardEvent<HTMLDivElement>) => {const moveNext = () => {const nextIndex = activeIndex + 1;setActiveIndex(nextIndex > value.length - 1 ? (loop ? 0 : -1) : nextIndex);};const movePrev = () => {const prevIndex = activeIndex - 1;setActiveIndex(prevIndex < 0 ? value.length - 1 : prevIndex);};if ((e.key === "Backspace" || e.key === "Delete") && value.length > 0) {if (inputValue.length === 0) {if (activeIndex !== -1 && activeIndex < value.length) {onValueChange(value.filter((item) => item !== value[activeIndex]));const newIndex = activeIndex - 1 < 0 ? 0 : activeIndex - 1;setActiveIndex(newIndex);} else {onValueChange(value.filter((item) => item !== value[value.length - 1]));}}} else if (e.key === "Enter") {setOpen(true);} else if (e.key === "Escape") {if (activeIndex !== -1) {setActiveIndex(-1);} else {setOpen(false);}} else if (dir === "rtl") {if (e.key === "ArrowRight") {movePrev();} else if (e.key === "ArrowLeft" && (activeIndex !== -1 || loop)) {moveNext();}} else {if (e.key === "ArrowLeft") {movePrev();} else if (e.key === "ArrowRight" && (activeIndex !== -1 || loop)) {moveNext();}}},[value, inputValue, activeIndex, loop]);return (<MultiSelectContext.Providervalue={{value,onValueChange: onValueChangeHandler,open,setOpen,inputValue,setInputValue,activeIndex,setActiveIndex,options,}}><CommandonKeyDown={handleKeyDown}className={cn("overflow-visible bg-transparent flex flex-col",className)}dir={dir}{...props}>{children}</Command></MultiSelectContext.Provider>);
};const MultiSelectorTrigger = forwardRef<HTMLDivElement,React.HTMLAttributes<HTMLDivElement>
>(({ className, children, ...props }, ref) => {const { value, onValueChange, activeIndex, open, options } = useMultiSelect();const mousePreventDefault = useCallback((e: React.MouseEvent) => {e.preventDefault();e.stopPropagation();}, []);const valueOptions = options.filter(option => value.includes(option.value))return (<divref={ref}className={cn("min-h-9 bg-accent text-sm flex items-center flex-wrap gap-1 px-3 rounded-lg mb-2",open ? "ring-ring ring-1 ring-offset-1 bg-background" : "",className)}{...props}>{valueOptions.map((item, index) => (<Badgekey={item.value}color={item.color}className={cn("flex flex-wrap gap-1",activeIndex === index && "ring-2 ring-muted-foreground")}><span>{item.label}</span><buttonaria-label={`Remove ${item.label} option`}aria-roledescription="button to remove option"type="button"onMouseDown={mousePreventDefault}onClick={() => onValueChange(item.value)}><span className="sr-only">Remove {item.label} option</span><RemoveIcon className="h-4 w-4 hover:stroke-destructive" /></button></Badge>))}{children}</div>);
});MultiSelectorTrigger.displayName = "MultiSelectorTrigger";const MultiSelectorInput = forwardRef<React.ElementRef<typeof CommandPrimitive.Input>,React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
>(({ className, ...props }, ref) => {const { setOpen, inputValue, setInputValue, activeIndex, setActiveIndex } =useMultiSelect();return (<CommandPrimitive.Input{...props}ref={ref}value={inputValue}onValueChange={activeIndex === -1 ? setInputValue : undefined}onBlur={() => setOpen(false)}onFocus={() => setOpen(true)}onClick={() => setActiveIndex(-1)}className={cn("bg-transparent outline-none placeholder:text-muted-foreground flex-1",className,activeIndex !== -1 && "caret-transparent")}/>);
});MultiSelectorInput.displayName = "MultiSelectorInput";const MultiSelectorContent = forwardRef<HTMLDivElement,React.HTMLAttributes<HTMLDivElement>
>(({ children }, ref) => {const { open } = useMultiSelect();return (<div ref={ref} className="relative">{open && children}</div>);
});MultiSelectorContent.displayName = "MultiSelectorContent";const MultiSelectorList = forwardRef<React.ElementRef<typeof CommandPrimitive.List>,React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
>(({ className, children }, ref) => {return (<CommandListref={ref}className={cn("p-2 flex flex-col gap-2 rounded-md scrollbar-thin scrollbar-track-transparent transition-colors scrollbar-thumb-muted-foreground dark:scrollbar-thumb-muted scrollbar-thumb-rounded-lg w-full absolute bg-background shadow-md z-10 border border-muted top-0",className)}>{children}<CommandEmpty><span className="text-muted-foreground">No results found</span></CommandEmpty></CommandList>);
});MultiSelectorList.displayName = "MultiSelectorList";const MultiSelectorItem = forwardRef<React.ElementRef<typeof CommandPrimitive.Item>,{ value: string } & React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
>(({ className, value, children, ...props }, ref) => {const { value: Options, onValueChange, setInputValue } = useMultiSelect();const mousePreventDefault = useCallback((e: React.MouseEvent) => {e.preventDefault();e.stopPropagation();}, []);const isIncluded = Options.includes(value);return (<CommandItemref={ref}{...props}onSelect={() => {onValueChange(value);setInputValue("");}}className={cn("rounded-md cursor-pointer px-4 py-1.5 transition-colors flex justify-between ",className,isIncluded && "opacity-50 cursor-default",props.disabled && "opacity-50 cursor-not-allowed")}onMouseDown={mousePreventDefault}>{children}{isIncluded && <Check className="h-4 w-4" />}</CommandItem>);
});MultiSelectorItem.displayName = "MultiSelectorItem";export {MultiSelector,MultiSelectorTrigger,MultiSelectorInput,MultiSelectorContent,MultiSelectorList,MultiSelectorItem,
};
这个组件库实现了一个多选下拉框,包含选择、显示和过滤选项等功能。组件利用了 React 的上下文、钩子和基于 Radix UI 和 CMDK 的组合控件。
以下是对每个主要部分的详细分析:
多选组件的核心上下文与状态
1. 上下文与钩子
const MultiSelectContext = createContext<MultiSelectContextProps | null>(null);const useMultiSelect = () => {const context = useContext(MultiSelectContext);if (!context) {throw new Error("useMultiSelect must be used within MultiSelectProvider");}return context;
};
MultiSelectContext
是一个 React 上下文,用于共享多选组件的状态。useMultiSelect
是一个自定义钩子,用于方便地访问这个上下文。
2. MultiSelector 组件
const MultiSelector = ({values: value,onValuesChange: onValueChange,loop = false,className,children,dir,options,...props
}: MultiSelectorProps) => {const [inputValue, setInputValue] = useState("");const [open, setOpen] = useState<boolean>(false);const [activeIndex, setActiveIndex] = useState<number>(-1);const onValueChangeHandler = useCallback((val: string) => {if (value.includes(val)) {onValueChange(value.filter((item) => item !== val));} else {onValueChange([...value, val]);}},[value]);const handleKeyDown = useCallback((e: KeyboardEvent<HTMLDivElement>) => {// handle keyboard navigation and actions},[value, inputValue, activeIndex, loop]);return (<MultiSelectContext.Providervalue={{value,onValueChange: onValueChangeHandler,open,setOpen,inputValue,setInputValue,activeIndex,setActiveIndex,options,}}><CommandonKeyDown={handleKeyDown}className={cn("overflow-visible bg-transparent flex flex-col",className)}dir={dir}{...props}>{children}</Command></MultiSelectContext.Provider>);
};
MultiSelector
是整个多选组件的核心,负责管理状态并提供上下文。它使用 useState
管理输入值、打开状态和活动索引。通过 useCallback
创建 onValueChangeHandler
和 handleKeyDown
函数,用于处理选项的选择和键盘事件。
组件子部分
1. MultiSelectorTrigger
const MultiSelectorTrigger = forwardRef<HTMLDivElement,React.HTMLAttributes<HTMLDivElement>
>(({ className, children, ...props }, ref) => {const { value, onValueChange, activeIndex, open, options } = useMultiSelect();const mousePreventDefault = useCallback((e: React.MouseEvent) => {e.preventDefault();e.stopPropagation();}, []);const valueOptions = options.filter(option => value.includes(option.value))return (<divref={ref}className={cn("min-h-9 bg-accent text-sm flex items-center flex-wrap gap-1 px-3 rounded-lg mb-2",open ? "ring-ring ring-1 ring-offset-1 bg-background" : "",className)}{...props}>{valueOptions.map((item, index) => (<Badgekey={item.value}color={item.color}className={cn("flex flex-wrap gap-1",activeIndex === index && "ring-2 ring-muted-foreground")}><span>{item.label}</span><buttonaria-label={`Remove ${item.label} option`}aria-roledescription="button to remove option"type="button"onMouseDown={mousePreventDefault}onClick={() => onValueChange(item.value)}><span className="sr-only">Remove {item.label} option</span><RemoveIcon className="h-4 w-4 hover:stroke-destructive" /></button></Badge>))}{children}</div>);
});MultiSelectorTrigger.displayName = "MultiSelectorTrigger";
MultiSelectorTrigger
是一个用于显示已选择选项的组件。它使用 useMultiSelect
钩子从上下文获取状态,并渲染已选项的 Badge
组件。每个 Badge
组件包含一个按钮,用于移除该选项。
2. MultiSelectorInput
const MultiSelectorInput = forwardRef<React.ElementRef<typeof CommandPrimitive.Input>,React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
>(({ className, ...props }, ref) => {const { setOpen, inputValue, setInputValue, activeIndex, setActiveIndex } =useMultiSelect();return (<CommandPrimitive.Input{...props}ref={ref}value={inputValue}onValueChange={activeIndex === -1 ? setInputValue : undefined}onBlur={() => setOpen(false)}onFocus={() => setOpen(true)}onClick={() => setActiveIndex(-1)}className={cn("bg-transparent outline-none placeholder:text-muted-foreground flex-1",className,activeIndex !== -1 && "caret-transparent")}/>);
});MultiSelectorInput.displayName = "MultiSelectorInput";
MultiSelectorInput
是一个输入组件,用于处理用户输入。它使用 useMultiSelect
钩子从上下文获取状态,并根据输入值更新上下文中的 inputValue
。它还处理输入框的焦点和点击事件。
3. MultiSelectorContent
const MultiSelectorContent = forwardRef<HTMLDivElement,React.HTMLAttributes<HTMLDivElement>
>(({ children }, ref) => {const { open } = useMultiSelect();return (<div ref={ref} className="relative">{open && children}</div>);
});MultiSelectorContent.displayName = "MultiSelectorContent";
MultiSelectorContent
是一个包装组件,用于渲染多选内容。当上下文中的 open
状态为 true
时,显示其子组件。
4. MultiSelectorList
const MultiSelectorList = forwardRef<React.ElementRef<typeof CommandPrimitive.List>,React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
>(({ className, children }, ref) => {return (<CommandListref={ref}className={cn("p-2 flex flex-col gap-2 rounded-md scrollbar-thin scrollbar-track-transparent transition-colors scrollbar-thumb-muted-foreground dark:scrollbar-thumb-muted scrollbar-thumb-rounded-lg w-full absolute bg-background shadow-md z-10 border border-muted top-0",className)}>{children}<CommandEmpty><span className="text-muted-foreground">No results found</span></CommandEmpty></CommandList>);
});MultiSelectorList.displayName = "MultiSelectorList";
MultiSelectorList
是一个列表组件,用于渲染所有可选项。它使用 CommandList
组件,并在子组件中包含一个 CommandEmpty
组件,当没有结果时显示提示。
5. MultiSelectorItem
const MultiSelectorItem = forwardRef<React.ElementRef<typeof CommandPrimitive.Item>,{ value: string } & React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
>(({ className, value, children, ...props }, ref) => {const { value: Options, onValueChange, setInputValue } = useMultiSelect();const mousePreventDefault = useCallback((e: React.MouseEvent) => {e.preventDefault();e.stopPropagation();}, []);const isIncluded = Options.includes(value);return (<CommandItemref={ref}{...props}onSelect={() => {onValueChange(value);setInputValue("");}}className={cn("rounded-md cursor-pointer px-4 py-1.5 transition-colors flex justify-between ",className,isIncluded && "opacity-50 cursor-default",props.disabled && "opacity-50 cursor-not-allowed")}onMouseDown={mousePreventDefault}>{children}{isIncluded && <Check className="h-4 w-4" />}</CommandItem>);
});MultiSelectorItem.displayName = "MultiSelectorItem";
MultiSelectorItem
是一个可选项组件。它使用 useMultiSelect
钩子从上下文获取状态,并在选中时调用 onValueChange
更新上下文中的选项状态。它还会在已选项时显示一个 Check
图标。
总结
这个多选组件库通过上下文和钩子共享状态,并将组件划分为多个小组件,每个小组件负责处理不同的功能和渲染部分。
相关文章:
WHAT - 通过 shadcn 组件源码学习 React
目录 一、button1. 导入部分2. 定义按钮的样式变体1. variant2. size总结 3. 定义按钮的属性类型4. 定义按钮组件5. 导出组件和样式变体总结 二、multi-select多选组件的核心上下文与状态1. 上下文与钩子2. MultiSelector 组件 组件子部分1. MultiSelectorTrigger2. MultiSelec…...

grafana对接zabbix数据展示
目录 1、初始化、安装grafana 2、浏览器访问 3、安装zabbix 4、zabbix数据对接grafana 5、如何导入模板? ① 设置键值 ② 在zabbix web端完成自定义监控项 ③ garafana里添加nginx上面的的三个监控项 6、如何自定义监控项? 以下实验沿用上一篇z…...
C++ 学习补充 1:短链算法
短链算法 短链算法: 将长链接 转化为 一个短key 之所以不是短url 是因为 ,url 短链不区分大小写,可用空间比较小。 短链算法通常用于将一个长网址转换成一个较短的字符串,以便于分享和存储。这种算法通常需要满足以下条件&#…...

硅纪元视角 | 语音克隆突破:微软VALL-E 2,Deepfake新纪元!
在数字化浪潮的推动下,人工智能(AI)正成为塑造未来的关键力量。硅纪元视角栏目紧跟AI科技的最新发展,捕捉行业动态;提供深入的新闻解读,助您洞悉技术背后的逻辑;汇聚行业专家的见解,…...

没有51基础,能不能学好STM32?
在开始前刚好我有一些资料,是我根据网友给的问题精心整理了一份「STM32的资料从专业入门到高级教程」, 点个关注在评论区回复“888”之后私信回复“888”,全部无偿共享给大家!!! 我们通常准备攻读一本大部…...
Web开发:VUE3小白开发入门基础笔记
一、基本语法 1.click 后端路由:api/GetDataList 返回值:Value 前端要做的事: ①拿到Value值,传到a标签 ②a标签有一个按钮,每点击一下,Value的值加一。 前端需要用click语法 【代码】 <template>…...
技术周总结 2024.07.15~07.21周日(Spark性能优化)
文章目录 一、07.19 周五1.1)问题01: spark性能优化1.2)问题02: spark是怎么应用在机器学习领域的1.3)问题03:spark自带工具有哪些?1.4)问题04: spark日志的知识点有哪些…...
提高性能的常见技术
1.数据库层面: 读写分离,对于大部分业务来说,读取操作要大于写入,同一个库,既读又写的话,负载会比较重,拆分为读库和写入库,可以降低数据库的负载,分时或延迟将写入的数…...
LeetCode206 反转链表
前言 题目: 206. 反转链表 文档: 代码随想录——反转链表 编程语言: C 解题状态: 有了思路以后没敢尝试 思路 需要注意的是创建指针不会申请额外的内存空间。 代码 方法一: 双指针法/迭代 我的理解是创建了三个指针…...

nginx通过nginx_upstream_check_module实现后端健康检查
1、简介说明 nginx是常用的反向代理和负载均衡服务,具有强大并发能力、稳定性、丰富的功能集、低资源的消耗。 nginx自身是没有针对后端节点健康检查的,但是可以通过默认自带的ngx_http_proxy_module 模块和ngx_http_upstream_module模块中的相关指令来完…...
FastGPT 知识库搜索测试功能解析(二)
目录 一、代码解析 1.1 searchTest.ts 1.2 controller.ts 本文接上一篇文章FastGPT 知识库搜索测试功能解析 对具体代码进行解析。 一、代码解析 FastGPT 知识库的搜索测试功能主要涉及两个文件,分别是 searchTest.ts 和 controller.ts 文件,下面分别进行介绍。 1.1 se…...

双向链表<数据结构 C版>
目录 关于链表的分类 双向链表结构体 初始化 尾插 头插 打印 判断是否为空 尾删 头删 查找 指定位置之后的插入 指定位置的删除 销毁 关于链表的分类 根据链表的三大特性,单向or双向、带头or不带头、循环or不循环,可将链表分为2*2*2…...

react18+
主要是围绕函数式组件讲,18主要用就是函数式组件,学习前先熟悉下原生js的基本使用,主要是事件 1、UI操作 1.1、书写jsx标签语言 基本写法和原生如同一则,只是放在一个方法里面返回而已,我们称这样的写法为函数式组件…...

rk3568 OpenHarmony4.1 Launcher定制开发—桌面壁纸替换
Launcher 作为系统人机交互的首要入口,提供应用图标的显示、点击启动、卸载应用,并提供桌面布局设置以及最近任务管理等功能。本文将介绍如何使用Deveco Studio进行单独launcher定制开发、然后编译并下载到开发板,以通过Launcher修改桌面背景…...
MySQL:送分or送命 varchar(30) 与 int(10)
摘要: VARCHAR(30) 和 INT(10) 在MySQL中代表两种不同类型的字段,它们之间的主要区别在于它们存储的数据类型、存储方式以及显示宽度的含义。 正文: INT(10) 在MySQL中,当你看到INT(10)这样的数据类型定义时,可能会…...

【odoo17】后端py方法触发右上角提示组件
概要 在前面文章中,有介绍过前端触发的通知服务。 【odoo】右上角的提示(通知服务) 此文章则介绍后端触发方法。 内容 直接上代码:但是前提一定是按钮触发!!!!! def bu…...
1775D - Friendly Spiders
题目链接:Friendly Spiders 首先我们可以考虑暴力做法,那就是每两个蜘蛛判断一下gcd,如果不等于1,那就连条边,这样的话时间复杂度是O(n^2),显然超时,因此我们可以采用类似…...

【python】OpenCV—Point Polygon Test
文章目录 1、完整代码2、涉及到的库cv2.pointPolygonTestcv2.minMaxLoc 1、完整代码 from __future__ import print_function from __future__ import division import cv2 as cv import numpy as np # Create an image r 100 src np.zeros((4*r, 4*r), dtypenp.uint8) # 创…...
6 Go语言的常量、枚举、作用域
本专栏将从基础开始,循序渐进,由浅入深讲解Go语言,希望大家都能够从中有所收获,也请大家多多支持。 查看相关资料与知识库 专栏地址:Go专栏 如果文章知识点有错误的地方,请指正!大家一起学习,…...

第十一章 数据结构
第十一章 数据结构 11.1 数组 数组是元素的顺序集合,通常这些元素具有相同的数据类型 索引表示元素在数组中的顺序号,顺序号从数组开始处计数 数组元素通过索引被独立给出了地址,数组整体上有一个名称,但每个元素利用数组的的…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...

【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...

解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用
在工业制造领域,无损检测(NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统,以非接触式光学麦克风技术为核心,打破传统检测瓶颈,为半导体、航空航天、汽车制造等行业提供了高灵敏…...
OCR MLLM Evaluation
为什么需要评测体系?——背景与矛盾 能干的事: 看清楚发票、身份证上的字(准确率>90%),速度飞快(眨眼间完成)。干不了的事: 碰到复杂表格(合并单元…...
Python常用模块:time、os、shutil与flask初探
一、Flask初探 & PyCharm终端配置 目的: 快速搭建小型Web服务器以提供数据。 工具: 第三方Web框架 Flask (需 pip install flask 安装)。 安装 Flask: 建议: 使用 PyCharm 内置的 Terminal (模拟命令行) 进行安装,避免频繁切换。 PyCharm Terminal 配置建议: 打开 Py…...