mcpField
Y
ycs77-vue

ycs77-vue

github.com/ycs77开发038 次安装1 周前更新
代码仓库

关于 ycs77-vue

ycs77-vue 是面向 Vue 3 与 TypeScript 项目的编码规范技能,适合希望保持代码简洁、易读的开发者。它涵盖单文件组件结构、类型声明和响应式状态等约定。

主要功能

  1. 01TypeScript 格式约定
  2. 02Vue 单文件组件区块顺序
  3. 03内联 props 与 emits 类型
  4. 04使用 reactive() 管理表单状态
  5. 05复杂类型的 ref() 写法
  6. 06模板中的 props 访问规则

适用场景

  1. 01统一 Vue 3 项目的代码风格
  2. 02编写组件时组织 props 与 emits 类型
  3. 03管理表单及复杂响应式状态

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/ycs77/skills --skill ycs77-vue

安装后在 Claude Code 中输入/ycs77-vue确认已加载。

详细介绍

Lucas Yang 的 Vue 约定

面向真实项目的 Vue 3 和 TypeScript 实践,注重减少样板代码、提高可读性和实用简洁性。

TypeScript 格式

标准:2 个空格、单引号、不加分号、保留尾随逗号。

Vue SFC 模式

1. SFC 块顺序

在单文件组件中,始终将 <template> 放在 <script setup lang="ts"> 之前。这符合自然的阅读顺序:先看结构(要渲染什么),再看行为(如何运作)。

良好示例:

<template>
  <div class="container">
    <h1>{{ title }}</h1>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const title = ref('Hello World')
</script>
2. 内联 Props/Emits 类型

优先在 defineProps 和 defineEmits 中使用内联类型,以便在调用处查看组件 API。

良好示例:

<script setup lang="ts">
const props = defineProps<{
  title: string
  count?: number
  items: {
    id: string
    name: string
  }[]
}>()

const emit = defineEmits<{
  update: [value: string]
  delete: [id: string]
}>()
</script>

例外情况:只有当类型在多个组件中重复使用或需要导出时,才将其提取为单独的接口。

3. 使用 reactive() 管理表单状态

管理表单状态时,优先使用 reactive() 创建一个包含所有表单字段的响应式对象。与为每个字段分别调用多个 ref() 相比,这种方式能简化状态管理并减少样板代码。

良好示例:

<template>
  <form @submit.prevent="handleSubmit">
    <input v-model="form.email" type="email">
    <input v-model="form.password" type="password">
    <input v-model="form.rememberMe" type="checkbox">
  </form>
</template>

<script setup lang="ts">
import { reactive } from 'vue'

const form = reactive({
  email: '',
  password: '',
  rememberMe: false,
})

function handleSubmit() {
  console.log(form) // Clean object or reactive object, easy to submit
}

function resetForm() {
  form.email = ''
  form.password = ''
  form.rememberMe = false
}
</script>

原因:将相关状态分组可减少 .value 样板代码,并使表单提交更简洁。只有对于真正独立的状态,才使用单独的 ref()。

4. 对复杂类型的 ref() 使用类型断言

对于接口或复杂对象类型,优先使用 ref(value) as Ref<Type>,而非 ref<Type>(value),以避免 Vue 深层解包导致的类型冲突。请确保该值符合断言的类型。对于基本类型和枚举类型,使用 ref<Type>()。

表示对象不存在时,优先使用 null 而非 undefined。

良好示例:

<script setup lang="ts">
import type { Ref } from 'vue'
import { ref } from 'vue'

interface User {
  id: number
  name: string
}

enum Status {
  Pending = 'pending',
}

// Complex type - use type assertion
const user = ref({ id: 1, name: 'Lucas' }) as Ref<User>
const users = ref([]) as Ref<User[]>
const isSelectedUser = ref(null) as Ref<User | null>

// Primitive types - generic parameter is fine
const count = ref<number>(0)
const isActive = ref<boolean>(false)
const status = ref<Status>(Status.Pending)
</script>

避免:

<script setup lang="ts">
import type { User } from '@/types'
import { ref } from 'vue'

// May cause: Type '...' is not assignable to type 'Ref<User>'
const user = ref<User>()
</script>
5. 绑定使用同名简写

在 Vue 3.4+ 中,为名称匹配的绑定使用同名简写。

良好示例:

<template>
  <div :id :title>
    <MyComponent :user-name :count :is-active />
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const id = ref('app')
const title = ref('Dashboard')
const userName = ref('Lucas')
const count = ref(42)
const isActive = ref(true)
</script>

原因::user-name 与 userName 匹配(从 kebab-case 转为 camelCase)。如果绑定需要显式使用 props. 访问(第 6 节),则使用完整形式。

6. 在模板中直接访问 Props

通过 defineProps 声明的 Props 可在 <template> 中按名称访问。在不产生歧义时,优先使用 {{ title }} 而非 {{ props.title }}。当局部绑定遮蔽了某个 prop 时,使用 props.name。对于 class(JavaScript 保留字)和 as(用于 TypeScript 类型断言)等语法敏感的名称,请显式访问 Props:props.class 和 props.as。不能将单独的 class 用作 :class 简写的表达式;:is="as" 则不会明确指出 as 的来源。

良好示例:

<template>
  <div :class="props.class">
    <h1>{{ title }}</h1>
    <component :is="props.as">content</component>
  </div>
</template>

<script setup lang="ts">
import type { HTMLAttributes } from 'vue'

const props = defineProps<{
  title: string
  as: string
  class?: HTMLAttributes['class']
}>()
</script>

避免:

<div :class>
  <component :is="as">content</component>
</div>

评论

支持 Markdown