现代 Vue 全栈开发实战:Vue 3.5 + TypeScript + Vite 7 + Tailwind CSS v4 + shadcn-vue + TanStack Query

约 9 分钟阅读

引言:拥抱现代化 Vue 生态

随着 Vue 3.5、Vite 7 和 Tailwind CSS v4 的发布,Vue 生态迎来了新一轮的性能与开发体验提升。shadcn-vue 提供了精美的 UI 组件,而 TanStack Query(原 React Query)则为 Vue 带来了强大的数据获取与状态管理能力。

Nidalee 项目中,我们整合了这套全栈技术栈,实现了高性能、类型安全、美观且易于维护的桌面应用。本文将以“主题系统”为例,带你从零搭建一个现代化 Vue 项目,涵盖项目初始化、核心配置和关键代码实现。

技术选型概览

  • Vue 3.5: 最新的 Vue 核心,带来更好的性能和新特性。
  • TypeScript: 提供静态类型检查,增强代码健壮性。
  • Vite 7: 极速的构建工具,提供开箱即用的热更新。
  • Tailwind CSS v4: 下一代 CSS 框架,配置驱动,原子化 CSS。
  • shadcn-vue: 基于 Radix UI 和 Tailwind CSS 的高质量 Vue 组件库。
  • TanStack Query (Vue): 强大的异步状态管理库,简化数据获取、缓存和更新。

1. 项目初始化

首先,使用 pnpm(或你偏好的包管理器)创建一个新项目:

bash
# 创建 Vite 项目
pnpm create vite@latest my-vue-app --template vue-ts
cd my-vue-app

# 安装依赖
pnpm install

# 安装 Tailwind CSS v4
pnpm add -D tailwindcss@next @tailwindcss/vite

# 初始化 Tailwind CSS
npx tailwindcss init -p

2. 配置 Tailwind CSS v4

Tailwind CSS v4 采用了全新的配置方式。编辑 tailwind.config.js

js
// tailwind.config.js
export default {
  content: [
    "./index.html",
    "./src/**/*.{vue,js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}

然后在 src/style.css 中引入 Tailwind:

css
/* src/style.css */
@import 'tailwindcss';

3. 配置 Vite 7 与 TypeScript

编辑 vite.config.ts 以启用 Tailwind 插件和 TypeScript 支持:

ts
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import tailwindcss from '@tailwindcss/vite'

export default defineConfig({
  plugins: [
    vue(),
    tailwindcss(),
  ],
})

确保 tsconfig.json 正确配置了路径映射和模块解析:

json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    },
    "target": "ES2020",
    "useDefineForClassFields": true,
    "module": "ESNext",
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "skipLibCheck": true,
    "moduleResolution": "bundler",
    "allowImportingTsExtensions": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "preserve",
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true
  },
  "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
}

4. 集成 shadcn-vue

安装 shadcn-vue 及其依赖:

bash
pnpm add shadcn-vue lucide-vue-next class-variance-authority clsx tailwind-merge

初始化 shadcn-vue

bash
npx shadcn-vue@latest init

这会生成一个 components.json 配置文件,并在 src/components 下创建 ui 目录。你可以通过 CLI 添加组件,例如按钮:

bash
npx shadcn-vue@latest add button

5. 集成 TanStack Query (Vue)

安装 @tanstack/vue-query

bash
pnpm add @tanstack/vue-query

src/main.ts 中配置插件:

ts
// src/main.ts
import { createApp } from 'vue'
import { VueQueryPlugin, QueryClient } from '@tanstack/vue-query'
import App from './App.vue'
import './style.css'

const app = createApp(App)
const queryClient = new QueryClient()

app.use(VueQueryPlugin, { queryClient })
app.mount('#app')

6. 实战:构建主题系统

我们将构建一个简单的主题系统,允许用户在浅色和深色模式之间切换,并动态改变主题色。

6.1. 主题状态管理

使用 Pinia 来管理主题状态。首先安装 Pinia:

bash
pnpm add pinia

创建一个 store src/stores/themeStore.ts

ts
// src/stores/themeStore.ts
import { defineStore } from 'pinia'
import { ref, watch } from 'vue'

export const useThemeStore = defineStore('theme', () => {
  const isDark = ref(false)
  const primaryColor = ref('#3b82f6') // 默认蓝色

  // 监听主题变化并应用到 DOM
  watch(isDark, (newVal) => {
    if (newVal) {
      document.documentElement.classList.add('dark')
    } else {
      document.documentElement.classList.remove('dark')
    }
  }, { immediate: true })

  // 监听主色变化并更新 CSS 变量
  watch(primaryColor, (newVal) => {
    document.documentElement.style.setProperty('--color-primary', newVal)
  }, { immediate: true })

  function toggleDark() {
    isDark.value = !isDark.value
  }

  function setPrimaryColor(color: string) {
    primaryColor.value = color
  }

  return { isDark, primaryColor, toggleDark, setPrimaryColor }
})

6.2. 应用根组件

src/App.vue 中使用 store 并提供切换功能:

vue
<!-- src/App.vue -->
<script setup lang="ts">
import { useThemeStore } from '@/stores/themeStore'
import { Button } from '@/components/ui/button'

const themeStore = useThemeStore()
</script>

<template>
  <div id="app" class="min-h-screen bg-background text-foreground flex flex-col items-center justify-center gap-4">
    <h1 class="text-3xl font-bold">Modern Vue App</h1>
    <p class="text-muted-foreground">Built with Vue 3.5, Vite 7, Tailwind CSS v4, shadcn-vue, and TanStack Query</p>

    <div class="flex gap-2">
      <Button @click="themeStore.toggleDark">
        切换 {{ themeStore.isDark ? '浅色' : '深色' }} 模式
      </Button>
      <Button @click="themeStore.setPrimaryColor('#ef4444')" variant="outline">
        红色主题
      </Button>
      <Button @click="themeStore.setPrimaryColor('#10b981')" variant="outline">
        绿色主题
      </Button>
    </div>

    <div class="mt-8 p-4 bg-card text-card-foreground rounded-lg shadow-sm border">
      <p>这是一个卡片组件,展示了 shadcn-vue 的样式。</p>
    </div>
  </div>
</template>

6.3. Tailwind CSS 配置

为了让主题切换和颜色自定义生效,我们需要在 src/style.css 中定义 CSS 变量,并在 Tailwind 配置中引用它们:

css
/* src/style.css */
@import 'tailwindcss';

@theme {
  --radius: 0.5rem;
}

@theme inline {
  --color-background: var(--background);
  --color-foreground: var(--foreground);
  --color-card: var(--card);
  --color-card-foreground: var(--card-foreground);
  --color-primary: var(--primary);
  --color-primary-foreground: var(--primary-foreground);
  --color-muted: var(--muted);
  --color-muted-foreground: var(--muted-foreground);
  --color-border: var(--border);
}

@layer base {
  :root {
    --background: 0 0% 100%;
    --foreground: 240 10% 3.9%;
    --card: 0 0% 100%;
    --card-foreground: 240 10% 3.9%;
    --primary: var(--color-primary); /* 使用动态变量 */
    --primary-foreground: 0 0% 98%;
    --muted: 240 4.8% 95.9%;
    --muted-foreground: 240 3.8% 46.1%;
    --border: 240 5.9% 90%;
  }

  .dark {
    --background: 240 10% 3.9%;
    --foreground: 0 0% 98%;
    --card: 240 10% 3.9%;
    --card-foreground: 0 0% 98%;
    --primary: var(--color-primary); /* 使用动态变量 */
    --primary-foreground: 0 0% 98%;
    --muted: 240 3.7% 15.9%;
    --muted-foreground: 240 5% 64.9%;
    --border: 240 3.7% 15.9%;
  }
}

body {
  background-color: hsl(var(--background));
  color: hsl(var(--foreground));
  margin: 0;
}

#app {
  min-height: 100vh;
}

6.4. 使用 TanStack Query 获取数据

假设我们需要从一个 API 获取主题配置。我们可以创建一个 composable 来封装查询逻辑:

ts
// src/composables/useThemeConfig.ts
import { useQuery } from '@tanstack/vue-query'

interface ThemeConfig {
  defaultDarkMode: boolean
  defaultPrimaryColor: string
}

const fetchThemeConfig = async (): Promise<ThemeConfig> => {
  // 模拟 API 调用
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({
        defaultDarkMode: false,
        defaultPrimaryColor: '#3b82f6'
      })
    }, 1000)
  })
}

export const useThemeConfig = () => {
  return useQuery({
    queryKey: ['themeConfig'],
    queryFn: fetchThemeConfig,
    staleTime: 1000 * 60 * 5, // 5分钟
  })
}

然后在 App.vue 中使用它来初始化默认主题:

vue
<!-- src/App.vue (部分代码) -->
<script setup lang="ts">
import { useThemeStore } from '@/stores/themeStore'
import { useThemeConfig } from '@/composables/useThemeConfig'
import { Button } from '@/components/ui/button'
import { watch } from 'vue'

const themeStore = useThemeStore()
const { data: themeConfig, isLoading } = useThemeConfig()

// 当配置加载完成后,应用默认设置
watch(themeConfig, (config) => {
  if (config) {
    themeStore.isDark = config.defaultDarkMode
    themeStore.setPrimaryColor(config.defaultPrimaryColor)
  }
})
</script>

<template>
  <div id="app" class="min-h-screen bg-background text-foreground flex flex-col items-center justify-center gap-4">
    <div v-if="isLoading" class="text-muted-foreground">
      加载主题配置中...
    </div>
    <template v-else>
      <h1 class="text-3xl font-bold">Modern Vue App</h1>
      <p class="text-muted-foreground">Built with Vue 3.5, Vite 7, Tailwind CSS v4, shadcn-vue, and TanStack Query</p>

      <div class="flex gap-2">
        <Button @click="themeStore.toggleDark">
          切换 {{ themeStore.isDark ? '浅色' : '深色' }} 模式
        </Button>
        <Button @click="themeStore.setPrimaryColor('#ef4444')" variant="outline">
          红色主题
        </Button>
        <Button @click="themeStore.setPrimaryColor('#10b981')" variant="outline">
          绿色主题
        </Button>
      </div>

      <div class="mt-8 p-4 bg-card text-card-foreground rounded-lg shadow-sm border">
        <p>这是一个卡片组件,展示了 shadcn-vue 的样式。</p>
      </div>
    </template>
  </div>
</template>

7. 总结

通过整合 Vue 3.5、TypeScript、Vite 7、Tailwind CSS v4、shadcn-vue 和 TanStack Query,我们构建了一个现代化、高性能且易于维护的前端应用。这套技术栈不仅提供了卓越的开发体验,还确保了最终产品的质量和性能。

“主题系统”的实现展示了如何将这些技术协同工作:Tailwind CSS v4 的原子化和配置驱动特性让样式管理变得简单;shadcn-vue 提供了美观且一致的 UI 组件;TanStack Query 简化了复杂的数据获取逻辑;而 Pinia 则优雅地管理了全局状态。

这套组合拳为现代 Vue 应用开发提供了一个坚实的起点,无论你是构建企业级应用还是个人项目,都能从中受益。

相关文章