Vue开发技能 vue-development

Vue 3开发技能,专注于组合式API、响应式系统、组件模式、TypeScript集成和最佳实践。提供Vue 3应用程序构建的专家级指导,包括组件开发、状态管理、路由配置、依赖注入等核心功能。适用于前端开发人员构建现代化、可维护的Vue应用。关键词:Vue 3开发,组合式API,TypeScript集成,前端框架,响应式编程,组件化开发,Vue Router,状态管理,前端架构

前端开发 0 次安装 0 次浏览 更新于 2/26/2026

name: vue-development description: 使用组合式API、响应式系统、组件模式、TypeScript集成和最佳实践进行Vue 3开发 allowed-tools: 读取, 写入, 编辑, Bash, Glob, Grep

Vue开发技能

为使用组合式API和现代模式构建Vue 3应用程序提供专家级协助。

能力

  • 使用组合式API创建Vue 3组件
  • 使用ref和reactive实现响应式状态
  • 构建可复用逻辑的组合式函数
  • 配置Vue与TypeScript
  • 设置Vue Router和导航守卫
  • 实现provide/inject进行依赖注入

使用场景

在以下情况时调用此技能:

  • 创建Vue 3组件
  • 构建共享逻辑的组合式函数
  • 设置Vue项目结构
  • 实现响应式模式
  • 配置Vue与TypeScript

输入参数

参数 类型 必填 描述
componentName 字符串 组件名称(帕斯卡命名法)
compositionApi 布尔值 使用组合式API(默认:true)
typescript 布尔值 使用TypeScript(默认:true)
scriptSetup 布尔值 使用script setup语法(默认:true)

配置示例

{
  "componentName": "UserProfile",
  "compositionApi": true,
  "typescript": true,
  "scriptSetup": true,
  "features": ["props", "emits", "slots"]
}

组件模式

Script Setup组件

<!-- components/UserProfile.vue -->
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue';

interface User {
  id: string;
  name: string;
  email: string;
  avatar: string;
}

// 带默认值的Props
const props = withDefaults(defineProps<{
  user: User;
  editable?: boolean;
}>(), {
  editable: false,
});

// 类型化的Emits
const emit = defineEmits<{
  update: [user: User];
  delete: [id: string];
}>();

// 响应式状态
const isEditing = ref(false);
const editedName = ref(props.user.name);

// 计算属性
const initials = computed(() => {
  return props.user.name
    .split(' ')
    .map(n => n[0])
    .join('')
    .toUpperCase();
});

// 方法
function saveChanges() {
  emit('update', { ...props.user, name: editedName.value });
  isEditing.value = false;
}

// 生命周期
onMounted(() => {
  console.log('UserProfile mounted');
});

// 向父组件暴露
const resetForm = () => {
  editedName.value = props.user.name;
  isEditing.value = false;
};

defineExpose({
  resetForm,
});
</script>

<template>
  <div class="user-profile">
    <div class="avatar">
      <img v-if="user.avatar" :src="user.avatar" :alt="user.name" />
      <span v-else class="initials">{{ initials }}</span>
    </div>

    <div class="info">
      <template v-if="isEditing">
        <input v-model="editedName" @keyup.enter="saveChanges" />
        <button @click="saveChanges">保存</button>
        <button @click="isEditing = false">取消</button>
      </template>
      <template v-else>
        <h2>{{ user.name }}</h2>
        <p>{{ user.email }}</p>
        <button v-if="editable" @click="isEditing = true">编辑</button>
      </template>
    </div>

    <slot name="actions" :user="user" />
  </div>
</template>

<style scoped>
.user-profile {
  display: flex;
  gap: 1rem;
  padding: 1rem;
}

.avatar {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  overflow: hidden;
}

.initials {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  background: #e5e7eb;
  font-weight: bold;
}
</style>

组合式函数模式

// composables/useUser.ts
import { ref, computed, readonly } from 'vue';

interface User {
  id: string;
  name: string;
  email: string;
}

export function useUser(userId: string) {
  const user = ref<User | null>(null);
  const loading = ref(false);
  const error = ref<Error | null>(null);

  const isAuthenticated = computed(() => !!user.value);

  async function fetchUser() {
    loading.value = true;
    error.value = null;

    try {
      const response = await fetch(`/api/users/${userId}`);
      if (!response.ok) throw new Error('获取用户失败');
      user.value = await response.json();
    } catch (e) {
      error.value = e as Error;
    } finally {
      loading.value = false;
    }
  }

  async function updateUser(data: Partial<User>) {
    if (!user.value) return;

    loading.value = true;
    try {
      const response = await fetch(`/api/users/${userId}`, {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(data),
      });
      user.value = await response.json();
    } catch (e) {
      error.value = e as Error;
    } finally {
      loading.value = false;
    }
  }

  return {
    user: readonly(user),
    loading: readonly(loading),
    error: readonly(error),
    isAuthenticated,
    fetchUser,
    updateUser,
  };
}

// composables/useLocalStorage.ts
import { ref, watch } from 'vue';

export function useLocalStorage<T>(key: string, defaultValue: T) {
  const stored = localStorage.getItem(key);
  const data = ref<T>(stored ? JSON.parse(stored) : defaultValue);

  watch(
    data,
    (newValue) => {
      localStorage.setItem(key, JSON.stringify(newValue));
    },
    { deep: true }
  );

  return data;
}

Provide/Inject模式

// context/theme.ts
import { provide, inject, ref, type Ref, type InjectionKey } from 'vue';

type Theme = 'light' | 'dark';

interface ThemeContext {
  theme: Ref<Theme>;
  toggleTheme: () => void;
}

const ThemeKey: InjectionKey<ThemeContext> = Symbol('theme');

export function provideTheme() {
  const theme = ref<Theme>('light');

  function toggleTheme() {
    theme.value = theme.value === 'light' ? 'dark' : 'light';
  }

  provide(ThemeKey, { theme, toggleTheme });

  return { theme, toggleTheme };
}

export function useTheme() {
  const context = inject(ThemeKey);
  if (!context) {
    throw new Error('useTheme必须在theme provider内部使用');
  }
  return context;
}

Vue Router设置

// router/index.ts
import { createRouter, createWebHistory } from 'vue-router';
import type { RouteRecordRaw } from 'vue-router';

const routes: RouteRecordRaw[] = [
  {
    path: '/',
    component: () => import('@/layouts/DefaultLayout.vue'),
    children: [
      {
        path: '',
        name: 'home',
        component: () => import('@/views/Home.vue'),
      },
      {
        path: 'dashboard',
        name: 'dashboard',
        component: () => import('@/views/Dashboard.vue'),
        meta: { requiresAuth: true },
      },
    ],
  },
  {
    path: '/login',
    name: 'login',
    component: () => import('@/views/Login.vue'),
  },
];

const router = createRouter({
  history: createWebHistory(),
  routes,
});

// 导航守卫
router.beforeEach((to, from, next) => {
  const isAuthenticated = !!localStorage.getItem('token');

  if (to.meta.requiresAuth && !isAuthenticated) {
    next({ name: 'login', query: { redirect: to.fullPath } });
  } else {
    next();
  }
});

export default router;

最佳实践

  • 使用script setup语法以获得更简洁的组件
  • 创建组合式函数用于可复用逻辑
  • 正确类型化props和emits
  • 使用readonly修饰暴露的响应式状态
  • 利用provide/inject进行深层依赖传递

目标流程

  • vue应用开发
  • vue组件库
  • nuxt全栈开发
  • 前端架构