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

vue3入门- script setup详解下

  • defineProps() 和 defineEmits()
    • 针对TS类型的 props/emit 声明
    • 响应式 Props 解构
    • 使用类型声明时的默认 props 值
  • defineModel()
    • WARNING
    • 修饰符和转换器
    • 在 TypeScript 中使用
    • Record 语法
  • defineExpose()
  • defineSlots()
    • 多插槽示例
    • 父组件如何传递插槽
    • 子组件如何传值给父组件
    • 类型推断和 IDE 提示
    • 可选插槽和返回值类型
  • useSlots() 和 useAttrs()
  • 泛型
  • 限制

defineProps() 和 defineEmits()

为了在声明 propsemits 选项时获得完整的类型推导支持,我们可以使用 definePropsdefineEmits API,它们将自动地在 <script setup> 中可用:

<template><div><h1>{{ props.foo }}</h1><button @click="handleChange">Change</button><button @click="handleDelete">Delete</button></div>
</template><script setup>
const props = defineProps({foo: String
})const emit = defineEmits(['change', 'delete'])function handleChange() {emit('change', props.foo)
}function handleDelete() {emit('delete')
}
</script>
  • definePropsdefineEmits 都是只能在 <script setup> 中使用的编译器宏。他们不需要导入,且会随着 <script setup> 的处理过程一同被编译掉。
  • defineProps 接收与 props 选项相同的值,defineEmits 接收与 emits 选项相同的值。
  • definePropsdefineEmits 在选项传入后,会提供恰当的类型推导。

针对TS类型的 props/emit 声明

propsemit 也可以通过给 definePropsdefineEmits 传递纯TS类型参数的方式来声明:

const props = defineProps<{foo: stringbar?: number
}>()const emit = defineEmits<{(e: 'change', id: number): void(e: 'update', value: string, status: boolean): void
}>()// 3.3+:另一种更简洁的语法
const emit = defineEmits<{change: [id: number] // 具名元组语法update: [value: string, status: boolean]
}>()
  • definePropsdefineEmits 要么使用运行时声明,要么使用类型声明。同时使用两种声明方式会导致编译报错。

    • 示例 1: 使用运行时声明

      const props = defineProps({foo: String,bar: Number
      })const emit = defineEmits(['change', 'delete'])
      
    • 示例 2: 使用类型声明

      const props = defineProps<{foo: stringbar?: number
      }>()const emit = defineEmits<{(e: 'change', id: number): void(e: 'delete'): void
      }>()
      
    • 错误示例: 同时使用运行时声明和类型声明

      // ❌ 会导致编译报错
      const props = defineProps<{foo: string
      }>({bar: Number
      })
      
      // ❌ 会导致编译报错
      const emit = defineEmits<{(e: 'change', id: number): void
      }>(['delete'])
      
  • 使用类型声明的时候,静态分析会自动生成等效的运行时声明,从而在避免双重声明的前提下确保正确的运行时行为。

    • 在开发模式下,编译器会试着从类型来推导对应的运行时验证。例如这里从 foo: string 类型中推断出 foo: String。如果类型是对导入类型的引用,这里的推导结果会是 foo: null (与 any 类型相等),因为编译器没有外部文件的信息。
    • 在生产模式下,编译器会生成数组格式的声明来减少打包体积 (这里的 props 会被编译成 ['foo', 'bar'])。

在 Vue 3.2 及以下版本中,defineProps() 的泛型类型参数只能使用类型字面量或本地接口的引用:

interface Props {foo: stringbar?: number
}const props = defineProps<Props>()

在 Vue 3.3 及以上版本中,可以在类型参数的位置引用导入的类型或有限的复杂类型:

import { SomeType } from './types'const props = defineProps<SomeType>()

然而,仍然无法使用需要实际类型分析的复杂类型,例如条件类型:

// ❌ 不支持
type ConditionalProps<T> = T extends string ? { foo: T } : { bar: T }const props = defineProps<ConditionalProps<number>>()

但可以在单个 prop 的类型上使用条件类型:

// ✅ 支持
const props = defineProps<{foo: string | numberbar: string extends 'test' ? number : boolean
}>()

响应式 Props 解构

在 Vue 3.5 及以上版本中,从 defineProps 返回值解构出的变量是响应式的。当在同一个 <script setup> 块中的代码访问从 defineProps 解构出的变量时,Vue 的编译器会自动在前面添加 props.

const { foo } = defineProps(['foo'])watchEffect(() => {// 在 3.5 之前仅运行一次// 在 3.5+ 版本中会在 "foo" prop 改变时重新运行console.log(foo)
})

以上编译成以下等效内容:

const props = defineProps(['foo'])watchEffect(() => {// `foo` 由编译器转换为 `props.foo`console.log(props.foo)
})

此外,你可以使用 JavaScript 原生的默认值语法声明 props 的默认值。这在使用基于类型的 props 声明时特别有用。

interface Props {msg?: stringlabels?: string[]
}const { msg = 'hello', labels = ['one', 'two'] } = defineProps<Props>()

使用类型声明时的默认 props 值

在 3.5 及以上版本中,当使用响应式 Props 解构时,可以自然地声明默认值。但在 3.4 及以下版本中,默认情况下并未启用响应式 Props 解构。为了用基于类型声明的方式声明 props 的默认值,需要使用 withDefaults 编译器宏:

interface Props {msg?: stringlabels?: string[]
}const props = withDefaults(defineProps<Props>(), {msg: 'hello',labels: () => ['one', 'two']
})

上面代码会被编译为等价的运行时 propsdefault 选项。此外,withDefaults 辅助函数提供了对默认值的类型检查,并确保返回的 props 的类型删除了已声明默认值的属性的可选标志。

在使用 withDefaults 时,如果默认值是可变引用类型(如数组或对象),应将其封装在函数中,以避免意外修改和外部副作用。以下是一个示例:

interface Props {items?: string[]config?: {theme: stringlayout: string}
}const props = withDefaults(defineProps<Props>(), {items: () => ['item1', 'item2', 'item3'], // 使用函数返回数组config: () => ({ theme: 'dark', layout: 'grid' }) // 使用函数返回对象
})

在上述代码中,itemsconfig 的默认值是通过函数返回的。这确保了每个组件实例都能获得独立的默认值副本,而不会因为共享同一个引用而导致意外的修改。

  • 错误示例

如果直接使用对象或数组作为默认值,可能会导致所有组件实例共享同一个引用,从而引发意外行为:

const props = withDefaults(defineProps<Props>(), {items: ['item1', 'item2', 'item3'], // ❌ 直接使用数组config: { theme: 'dark', layout: 'grid' } // ❌ 直接使用对象
})

在这种情况下,修改一个组件实例的 itemsconfig 会影响其他实例的值,这是不符合预期的。

  • 使用默认值解构

当使用默认值解构时,不需要封装在函数中,因为解构操作会为每个实例创建独立的值:

const { items = ['item1', 'item2', 'item3'], config = { theme: 'dark', layout: 'grid' } } = defineProps<Props>()

这种方式同样可以确保每个组件实例获得自己的默认值副本。

defineModel()

这个宏可以用来声明一个双向绑定 prop,通过父组件的 v-model 来使用。组件 v-model 指南中也讨论了示例用法。

在底层,这个宏声明了一个 model prop 和一个相应的值更新事件。如果第一个参数是一个字符串字面量,它将被用作 prop 名称;否则,prop 名称将默认为 modelValue。在这两种情况下,你都可以再传递一个额外的对象,它可以包含 prop 的选项和 model ref 的值转换选项。

// 声明 "modelValue" prop,由父组件通过 v-model 使用
const model = defineModel()
// 或者:声明带选项的 "modelValue" prop
const model = defineModel({ type: String })// 在被修改时,触发 "update:modelValue" 事件
model.value = "hello"// 声明 "count" prop,由父组件通过 v-model:count 使用
const count = defineModel("count")
// 或者:声明带选项的 "count" prop
const count = defineModel("count", { type: Number, default: 0 })function inc() {// 在被修改时,触发 "update:count" 事件count.value++
}

在实际项目中,子组件可以用 defineModel 实现双向绑定:

// 子组件 CInput.vue

<template><input v-model="modelValue" placeholder="输入内容" />
</template><script setup lang="ts">
const modelValue = defineModel<string>({ default: '' })
</script>

// 父组件

<template><c-input v-model="inputval" /><div>{{ inputval }}</div>
</template>
<script setup>
import { ref } from 'vue';
import CInput from './components/CInput.vue';
const inputval = ref('')
</script>

WARNING

如果为 defineModel prop 设置了一个 default 值且父组件没有为该 prop 提供任何值,会导致父组件与子组件之间不同步。在下面的示例中,父组件的 myRef 是 undefined,而子组件的 model 是 1:

// 子组件:
const model = defineModel({ default: 1 })// 父组件
const myRef = ref()
<Child v-model="myRef"></Child>

解决方法:在父组件初始化时为 v-model 绑定的变量设置默认值,使其与子组件的默认值保持一致。

// 父组件
const myRef = ref(1) // 初始化为与子组件默认值一致

修饰符和转换器

为了获取 v-model 指令使用的修饰符,我们可以像这样解构 defineModel() 的返回值:

// 父组件

<c-input v-model.trim="inputval" />

// 子组件

const [modelValue, modelModifiers] = defineModel()// 对应 v-model.trim
if (modelModifiers.trim) {// ...
}

当存在修饰符时,我们可能需要在读取或将其同步回父组件时对其值进行转换。我们可以通过使用 getset 转换器选项来实现这一点:

// 子组件

const [modelValue, modelModifiers] = defineModel({// get() 省略了,因为这里不需要它set(value) {// 如果使用了 .trim 修饰符,则返回裁剪过后的值if (modelModifiers.trim) {return value.trim()}// 否则,原样返回return value}
})

在 TypeScript 中使用

definePropsdefineEmits 一样,defineModel 也可以接收类型参数来指定 model 值和修饰符的类型:

  1. defineModel<string>()
const modelValue = defineModel<string>()
// ^? Ref<string | undefined>
  • defineModel<string>() 定义了一个 v-model,其类型为 string
  • 返回值是一个 Ref<string | undefined>,表示 modelValue 是一个响应式引用,可能是 string 类型,也可能是 undefined
  • 默认情况下,v-model 的值是可选的,因此会包含 undefined
  1. defineModel<string>({ required: true })
const modelValue = defineModel<string>({ required: true })
// ^? Ref<string>
  • 这里通过传递选项 { required: true },将 v-model 的值设置为必填。
  • 这意味着 modelValue 不再可能是 undefined,它的类型变为 Ref<string>
  • 这种用法适合需要确保 v-model 始终有值的场景。
  1. defineModel<string, "trim" | "uppercase">()
const [modelValue, modifiers] = defineModel<string, "trim" | "uppercase">()
// ^? Record<'trim' | 'uppercase', true | undefined>
  • 这里定义了一个带有修饰符的 v-model,例如 v-model.trimv-model.uppercase
  • 返回值是一个数组:
    1. modelValueRef<string | undefined>,表示响应式的模型值。
    2. modifiers 是一个对象,类型为 Record<'trim' | 'uppercase', true | undefined>,表示修饰符的状态。
      • 如果某个修饰符被使用(如 v-model.trim),对应的值为 true
      • 如果未使用,则为 undefined

Record 语法

Record 是 TypeScript 中的一个实用类型(Utility Type),用于构造一个对象类型,其键和值的类型都可以被明确指定。

Record 通常用于:

  1. 定义固定键值对的对象类型。
  2. 动态生成对象类型,避免手动重复定义。
Record<Keys, Type>
  • Keys: 对象的键的类型,通常是字符串字面量类型或联合类型。
  • Type: 对象的值的类型。
Record<'trim' | 'uppercase', true | undefined>

这段代码的含义是:创建一个对象类型,该对象的键是 trimuppercase,值是 trueundefined

等价于:

{trim: true | undefined;uppercase: true | undefined;
}
const options: Record<'trim' | 'uppercase', true | undefined> = {trim: true,uppercase: undefined,
};

在这个例子中,options 是一个对象,必须包含 trimuppercase,并且它们的值只能是 trueundefined

defineExpose()

使用 <script setup> 的组件是默认关闭的——即通过模板引用或者 $parent 链获取到的组件的公开实例,不会暴露任何在 <script setup> 中声明的绑定。

可以通过 defineExpose 编译器宏来显式指定在 <script setup> 组件中要暴露出去的属性:

<script setup>
import { ref } from 'vue'const a = 1
const b = ref(2)defineExpose({a,b
})
</script>

当父组件通过模板引用的方式获取到当前组件的实例,获取到的实例会像这样 { a: number, b: number } (ref 会和在普通实例中一样被自动解包)

以下是一个关于如何使用 defineExpose 的实例讲解,展示如何在 <script setup> 中显式暴露属性,以便外部组件可以访问这些属性。

示例代码

  • 父组件 (ParentComponent.vue)

    <template><ChildComponent ref="childRef" /><button @click="callChildMethod">调用子组件方法</button>
    </template><script setup>
    import ChildComponent from './ChildComponent.vue';const childRef = useTemplateRef('childRef');function callChildMethod() {if (childRef.value) {childRef.value.exposedMethod(); // 调用子组件暴露的方法}
    }
    </script>
    
  • 子组件 (ChildComponent.vue)

    <template><div>子组件内容</div>
    </template><script setup>
    import { defineExpose } from 'vue';function exposedMethod() {console.log('子组件方法被调用');
    }// 使用 defineExpose 显式暴露方法
    defineExpose({exposedMethod,
    });
    </script>
    

defineSlots()

defineSlots 是 Vue 3 <script setup> 的编译宏,用于类型化插槽,让 TypeScript 能够对插槽名称和插槽 props 进行类型检查和智能提示。它只在编译阶段生效,不会影响运行时。

  • 类型安全:确保插槽名称和 props 类型正确,减少运行时错误。
  • IDE 提示:在编辑器中获得插槽相关的自动补全和类型提示。

基本语法如下

<script setup lang="ts">
const slots = defineSlots<{default(props: { msg: string }): any
}>()
// slots.default({ msg: 'hello' }) // 类型检查
</script>
  • 泛型参数是一个对象,键为插槽名称,值为函数类型。
  • 函数的参数是插槽 props 的类型,返回值类型通常用 any

多插槽示例

假设有一个组件支持多个插槽:

<script setup lang="ts">
const slots = defineSlots<{header(props: { title: string }): anydefault(props: { msg: string }): anyfooter(props: { count: number }): any
}>()
</script>
  • header 插槽要求 title 为字符串。
  • default 插槽要求 msg 为字符串。
  • footer 插槽要求 count 为数字。

父组件如何传递插槽

<template><Child class="child-style" expand><template #header="{ title }"><div>header部分描述:{{ title }}</div></template><template #default="{ count }"><p>default部分描述:{{ count }}</p></template><template #footer="{ msg }"><div>footer部分描述:{{ msg }}</div></template></Child>
</template>
<script setup>
import Child from './components/Child.vue';
</script>
  • 父组件传递的插槽参数会被类型检查,确保类型正确。

子组件如何传值给父组件

<template><slot name="header" headerDesc="顶部部分描述"></slot><slot defaultDesc="插槽描述">默认插槽描述</slot><slot name="footer" footerDesc="底部部分描述"></slot>
</template>
<script setup lang="ts">
const slots = defineSlots<{header(props: { headerDesc: string }):anyfooter( props: { footerDesc: string } ): anydefault( props: { defaultDesc: string } ): any
}>()
</script>

类型推断和 IDE 提示

<script setup> 中,使用 slots.header({ title: 'Hello' }) 时,IDE 会自动提示 title 必须是字符串,传递错误类型会报错。

可选插槽和返回值类型

你可以将插槽定义为可选:

<script setup lang="ts">
const slots = defineSlots<{header?(props: { title: string }): anydefault(props: { msg: string }): any
}>()
</script>
  • header? 表示 header 插槽是可选的。

返回值类型可以更具体:

<script setup lang="ts">
const slots = defineSlots<{default(props: { msg: string }): VNode[]
}>()
</script>

useSlots() 和 useAttrs()

<script setup> 中使用 slotsattrs 的情况相对较少,因为可以直接通过模板中的 $slots$attrs 访问它们。然而,在某些特定场景下,仍然可以使用 useSlotsuseAttrs 辅助函数来获取插槽和属性。

以下是一个实际使用 useSlotsuseAttrs 的示例:

  • 子组件 (ChildComponent.vue)

    <template><div v-bind="attrs"><slot name="header" /><p>子组件内容</p><slot /></div>
    </template><script setup>
    import { useSlots, useAttrs } from 'vue'const slots = useSlots()
    const attrs = useAttrs()// 检查是否提供了名为 "header" 的插槽
    if (!slots.header) {console.warn('未提供 header 插槽')
    }
    </script>
    
  • 父组件 (ParentComponent.vue)

    <template><ChildComponent class="custom-class"><template #header><h1>这是标题插槽内容</h1></template><p>这是默认插槽内容</p></ChildComponent>
    </template><script setup>
    import ChildComponent from './ChildComponent.vue'
    </script>
    

说明:

  1. useSlots:

    • 在子组件中使用 useSlots 检查是否提供了特定的插槽(如 header)。
    • 如果未提供插槽,输出警告信息。
  2. useAttrs:

    • 使用 useAttrs 获取父组件传递的属性(如 class="custom-class")。
    • 使用 v-bind="attrs" 将这些属性绑定到子组件的根元素。
  3. 父组件:

    • 通过 #header 提供了一个具名插槽。
    • 默认插槽内容直接放置在 <ChildComponent> 标签内。

运行结果:

  • 子组件会渲染标题插槽内容、默认插槽内容,并应用父组件传递的 class 属性。
  • 如果父组件未提供 header 插槽,子组件会在控制台输出警告信息。

泛型

可以使用 <script> 标签上的 generic 属性声明泛型类型参数:

<script setup lang="ts" generic="T">
defineProps<{items: T[]selected: T
}>()
</script>

generic 的值与 TypeScript 中位于 <...> 之间的参数列表完全相同。例如,你可以使用多个参数,extends 约束,默认类型和引用导入的类型:

<scriptsetuplang="ts"generic="T extends string | number, U extends Item"
>
import type { Item } from './types'
defineProps<{id: Tlist: U[]
}>()
</script>

为了在 ref 中使用泛型组件的引用,你需要使用 vue-component-type-helpers 库,因为 InstanceType 在这种场景下不起作用。

<scriptsetuplang="ts"
>
import componentWithoutGenerics from '../component-without-generics.vue'; // 一个没有泛型的普通组件。
import genericComponent from '../generic-component.vue'; // 一个带有泛型的组件。import type { ComponentExposed } from 'vue-component-type-helpers';// 适用于没有泛型的组件
ref<InstanceType<typeof componentWithoutGenerics>>();// 适用于有泛型的组件
ref<ComponentExposed<typeof genericComponent>>();

这段代码展示了如何在 Vue 3 的 <script setup> 中使用 TypeScript 来处理组件的引用,尤其是泛型组件的引用。以下是逐步的详细解释:

  1. 导入类型工具
import type { ComponentExposed } from 'vue-component-type-helpers';
  • vue-component-type-helpers 库中导入了 ComponentExposed 类型工具。
  • ComponentExposed 是一个辅助类型,用于提取组件的暴露类型(即组件实例的类型),特别适用于泛型组件。
  1. 处理没有泛型的组件引用
ref<InstanceType<typeof componentWithoutGenerics>>();
  • ref 是 Vue 的响应式 API,用于创建一个响应式引用。
  • InstanceType<typeof componentWithoutGenerics>
    • InstanceType 是 TypeScript 的内置工具类型,用于获取构造函数的实例类型。
    • typeof componentWithoutGenerics 获取组件的类型。
    • 结合起来,InstanceType<typeof componentWithoutGenerics> 表示 componentWithoutGenerics 的实例类型。
  • 适用于没有泛型的普通组件。
  1. 处理带有泛型的组件引用
ref<ComponentExposed<typeof genericComponent>>();
  • ref<ComponentExposed<typeof genericComponent>>
    • ComponentExposed 是从 vue-component-type-helpers 导入的类型工具。
    • typeof genericComponent 获取组件的类型。
    • ComponentExposed<typeof genericComponent> 提取了 genericComponent 的暴露类型。
  • 适用于带有泛型的组件,因为 InstanceType 无法正确处理泛型组件的类型。

总结:

  1. 普通组件:可以直接使用 InstanceType 获取实例类型。
  2. 泛型组件:需要借助 vue-component-type-helpers 提供的 ComponentExposed 类型工具,因为 InstanceType 无法正确处理泛型。

这种方式确保了在使用组件引用时,能够获得正确的类型推断和静态检查,提升了代码的安全性和可维护性。

为了更好地理解没有泛型的普通组件和带有泛型的组件的使用场景,以下是具体的示例讲解:

  • 没有泛型的普通组件

假设我们有一个普通的 Vue 组件 ButtonComponent.vue,它不使用任何泛型:

<!-- filepath: ButtonComponent.vue -->
<template><button>{{ label }}</button>
</template><script setup lang="ts">
defineProps<{label: string
}>();
</script>

<script setup> 中,我们可以通过 refInstanceType 来引用该组件的实例:

<script setup lang="ts">
import ButtonComponent from './ButtonComponent.vue';const buttonRef = ref<InstanceType<typeof ButtonComponent>>();
</script>

这里的 InstanceType<typeof ButtonComponent> 提供了 ButtonComponent 的实例类型,适用于没有泛型的普通组件。


  • 带有泛型的组件

假设我们有一个带有泛型的 Vue 组件 GenericList.vue,它接受一个泛型 T 来定义列表项的类型:

<!-- filepath: GenericList.vue -->
<template><ul><li v-for="(item, index) in items" :key="index">{{ item }}</li></ul>
</template><script setup lang="ts" generic="T">
defineProps<{items: T[]
}>();
</script>

<script setup> 中,我们需要使用 vue-component-type-helpers 提供的 ComponentExposed 来正确引用该组件的实例:

<script setup lang="ts">
import GenericList from './GenericList.vue';
import type { ComponentExposed } from 'vue-component-type-helpers';const listRef = ref<ComponentExposed<typeof GenericList>>();
</script>

这里的 ComponentExposed<typeof GenericList> 提取了 GenericList 的暴露类型,适用于带有泛型的组件,因为 InstanceType 无法正确处理泛型。

通过这些示例,我们可以清楚地看到如何在 Vue 3 的 <script setup> 中使用 TypeScript 来处理组件的引用,尤其是泛型组件的引用。

在 Vue 3.4 及以上版本,推荐使用 useTemplateRef 进行子组件引用,而不是直接用 refuseTemplateRef 能更好地处理类型推断,尤其是泛型组件。

<script setup lang="ts">
import componentWithoutGenerics from '../component-without-generics.vue'; // 没有泛型的组件
import genericComponent from '../generic-component.vue'; // 带泛型的组件
import type { ComponentExposed } from 'vue-component-type-helpers';// 没有泛型的组件引用
const normalRef = useTemplateRef<InstanceType<typeof componentWithoutGenerics>>('normalRef');// 带泛型的组件引用
const genericRef = useTemplateRef<ComponentExposed<typeof genericComponent>>('genericRef');
</script>

这样可以确保在 <script setup> 中获得正确的类型推断和 IDE 智能提示,无论是普通组件还是泛型组件。

限制

以下是一个关于 <script setup> 的实例讲解,帮助你理解其用法和限制。

假设我们有一个 Vue 3 组件,使用 <script setup> 来定义逻辑和模板。

<template><div><h1>{{ message }}</h1><button @click="increment">点击次数: {{ count }}</button></div>
</template><script setup lang="ts">
import { ref } from 'vue';// 定义响应式数据
const message = 'Hello, Vue 3!';
const count = ref(0);// 定义方法
const increment = () => {count.value++;
};
</script>

限制说明:

  1. 不能与 src 属性一起使用

    如果你尝试将 <script setup> 的逻辑提取到外部文件并通过 src 引入,会导致上下文丢失。例如:

    <script setup src="./logic.ts"></script>
    

    这种写法是不支持的,因为 <script setup> 的代码依赖于单文件组件的上下文。

  2. 不支持 DOM 内根组件模板
    <script setup> 不支持直接在 DOM 内使用根组件模板。例如:

    <div id="app"><MyComponent />
    </div>
    

    如果 MyComponent 使用了 <script setup>,它必须通过 Vue 的 createApp 挂载,而不能直接在 DOM 内使用。

http://www.xdnf.cn/news/1457101.html

相关文章:

  • (C题|NIPT 的时点选择与胎儿的异常判定)2025年高教杯全国大学生数学建模国赛解题思路|完整代码论文集合
  • 信息化安全性测试中漏洞扫描的定义与核心目的
  • 【DINOv3教程2-热力图】使用DINOv3直接生成图像热力图【附源码与详解】
  • Linux高手才知道的C++高性能I/O秘诀:Vector I/O与DMA深度解析
  • STM32实践项目(激光炮台)
  • git fetch 和 git pull 的区别
  • 一天涨幅2000倍的期权有吗?
  • OpenAI开放ChatGPT Projects功能,免费用户也能用了!
  • 类似于 Progress Telerik Fiddler Classic 的 免费 或 开源 HTTP/HTTPS 抓包与调试工具推荐
  • 哈希表-219.存在重复元素II-力扣(LeetCode)
  • Web 与 Nginx 网站服务:从基础到实践
  • 基于腾讯云MCP广场服务Firecrawl MCP网络采集服务构建自动化竞品监测工作日志
  • App UI 自动化环境搭建指南
  • oracle、mysql等基于结果创建数据
  • Oracle 数据库如何查询列
  • 驱动开发系列70 - vkQueueSubmit实现
  • ICPC Central Russia Regional Contest, 2024
  • 音频生成算法综述
  • 深度学习中的学习率优化策略详解
  • vue3入门- script setup详解上
  • 【深度学习】(9)--调整学习率
  • ACMESSL自动续签教程
  • 安徽某能源企业积极推进运维智能化转型,引入高压配电房机器人巡检系统
  • 笔记2 FreeRTOS任务
  • 如何在Spring Boot项目中使用MapStruct?
  • 旅游安全急救实训室助力应急处置技能实战化
  • Websocket的Key多少个字节
  • 【Big Data】云原生与AI时代的存储基石 Apache Ozone 的技术演进路径
  • 深度学习篇---SENet网络结构
  • 【C语言】第二课 基础语法