阅读视图

发现新文章,点击刷新页面。

从零开始:手把手教你创建 Vue 3 + TypeScript 项目

本文将带你一步步创建完整的 Vue 3 项目,包含现代化的开发工具链、代码规范和最佳实践。适合前端开发者学习和参考。

前言

Vue 3 带来了 Composition API、更好的 TypeScript 支持和性能优化,是现代前端开发的较广泛的选择。本教程将从环境搭建开始,逐步创建完整的 Vue 3 项目。

环境准备

1. Node.js 环境

Vue 3 项目需要 Node.js 环境,推荐使用 LTS 版本。

Windows 系统

# 访问 Node.js 官网下载安装包
# https://nodejs.org/

# 或使用 nvm-windows 管理多个版本
# 1. 下载 nvm-windows: https://github.com/coreybutler/nvm-windows/releases
# 2. 安装并重启命令行
nvm install 20.19.0
nvm use 20.19.0

macOS 系统

# 使用 Homebrew 安装
brew install node

# 或使用 nvm 管理版本
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
source ~/.bashrc
nvm install 20.19.0
nvm use 20.19.0

验证安装

# 检查版本
node --version  # 应显示 v20.19.0 或更高
npm --version   # 应显示 10.x.x 或更高

2. 包管理工具

推荐使用 npm 或 pnpm,yarn 也可以。

# 全局安装 pnpm (可选)
npm install -g pnpm

# 检查版本
pnpm --version

3. IDE 配置

推荐使用 VS Code,并安装 Vue 相关插件。

必需插件

  • Vue (Official) - Vue 官方插件,提供语法高亮和智能提示
  • TypeScript Importer - 自动导入 TypeScript 类型
  • Prettier - 代码格式化
  • ESLint - 代码检查

VS Code 设置

// .vscode/settings.json
{
  "typescript.preferences.importModuleSpecifier": "relative",
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.vscode-prettier",
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  }
}

项目创建

方法一:使用 Vite 官方模板

Vite 是 Vue 官方推荐的构建工具,速度快,开发体验好。

# 创建项目
npm create vue@latest vue-course

# 进入项目目录
cd vue-course

配置选项

在创建过程中选择以下配置:

✅ TypeScript
✅ JSX
✅ Vue Router
✅ Pinia
✅ ESLint
✅ Prettier

方法二:手动创建项目

如果你喜欢自定义配置,可以手动创建。

# 创建项目目录
mkdir vue-course
cd vue-course

# 初始化 package.json
npm init -y

# 安装核心依赖
npm install vue@latest @vue/compiler-sfc@latest
npm install -D @vitejs/plugin-vue@latest vite@latest
npm install -D typescript@latest vue-tsc@latest

项目配置

1. Vite 配置

创建 vite.config.ts 文件:

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { resolve } from 'path'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      '@': resolve(__dirname, 'src')
    }
  },
  server: {
    port: 5173,
    host: true,
    open: true
  },
  build: {
    target: 'esnext',
    minify: 'esbuild',
    outDir: 'dist'
  }
})

2. TypeScript 配置

创建 tsconfig.json

{
  "extends": "@vue/tsconfig/tsconfig.dom.json",
  "include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
  "exclude": ["src/**/__tests__/*"],
  "compilerOptions": {
    "composite": true,
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    },
    "types": ["vite/client"]
  }
}

创建 tsconfig.node.json

{
  "extends": "@vue/tsconfig/tsconfig.dom.json",
  "include": ["vite.config.*"],
  "compilerOptions": {
    "composite": true,
    "types": ["node"]
  }
}

创建 env.d.ts

/// <reference types="vite/client" />

declare module '*.vue' {
  import type { DefineComponent } from 'vue'
  const component: DefineComponent<{}, {}, any>
  export default component
}

3. ESLint 配置

创建 eslint.config.js

import js from '@eslint/js'
import vue from 'eslint-plugin-vue'
import typescript from '@typescript-eslint/eslint-plugin'
import typescriptParser from '@typescript-eslint/parser'

export default [
  {
    name: 'app/files-to-lint',
    files: ['**/*.{ts,mts,tsx,vue}'],
  },

  {
    name: 'app/files-to-ignore',
    ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'],
  },

  js.configs.recommended,
  ...vue.configs['flat/essential'],

  {
    name: 'app/vue-rules',
    files: ['**/*.vue'],
    languageOptions: {
      parser: vue.parser,
      parserOptions: {
        parser: typescriptParser,
        extraFileExtensions: ['.vue'],
        sourceType: 'module',
      },
    },
  },

  {
    name: 'app/typescript-rules',
    files: ['**/*.{ts,mts,tsx,vue}'],
    languageOptions: {
      parser: typescriptParser,
      parserOptions: {
        ecmaVersion: 2020,
        sourceType: 'module',
      },
    },
    rules: {
      ...typescript.configs.recommended.rules,
      '@typescript-eslint/no-unused-vars': 'error',
      '@typescript-eslint/explicit-function-return-type': 'off',
    },
  },
]

4. Prettier 配置

创建 .prettierrc.json

{
  "semi": false,
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "es5",
  "printWidth": 100,
  "endOfLine": "lf"
}

项目结构搭建

1. 基础文件结构

vue-course/
├── public/
│   ├── favicon.ico
├── src/
│   ├── assets/
│   │   ├── base.css
│   │   ├── main.css
│   │   └── logo.svg
│   ├── components/
│   │   ├── HelloWorld.vue
│   │   ├── TheWelcome.vue
│   │   ├── WelcomeItem.vue
│   │   └── icons/
│   ├── views/
│   │   ├── HomeView.vue
│   │   └── AboutView.vue
│   ├── router/
│   │   └── index.ts
│   ├── stores/
│   │   └── counter.ts
│   ├── App.vue
│   ├── main.ts
│   └── mcp-server.ts
├── .vscode/
│   └── settings.json
├── index.html
├── package.json
├── vite.config.ts
├── tsconfig.json
├── tsconfig.app.json
├── tsconfig.node.json
├── env.d.ts
├── eslint.config.ts
├── .prettierrc.json
└── README.md

2. 入口文件

src/main.ts

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import router from './router'
import App from './App.vue'

import './assets/main.css'

const app = createApp(App)

app.use(createPinia())
app.use(router)

app.mount('#app')

index.html

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vue Course</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.ts"></script>
  </body>
</html>

3. 根组件

src/App.vue

<template>
  <div id="app">
    <header class="app-header">
      <h1>Vue 3 项目</h1>
      <nav>
        <router-link to="/">首页</router-link>
        <router-link to="/about">关于</router-link>
      </nav>
    </header>

    <main class="app-main">
      <router-view />
    </main>
  </div>
</template>

<script setup lang="ts">
// 组件逻辑
</script>

<style scoped>
.app-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem 2rem;
  background: #f8f9fa;
  border-bottom: 1px solid #e9ecef;
}

.app-main {
  padding: 2rem;
  min-height: calc(100vh - 80px);
}
</style>

路由配置

1. 安装 Vue Router

npm install vue-router@4

2. 路由配置

src/router/index.ts

import { createRouter, createWebHistory } from 'vue-router'

const routes = [
  {
    path: '/',
    name: 'Home',
    component: () => import('../views/HomeView.vue'),
    meta: { title: '首页' }
  },
  {
    path: '/about',
    name: 'About',
    component: () => import('../views/AboutView.vue'),
    meta: { title: '关于' }
  }
]

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes
})

// 路由守卫
router.beforeEach((to, from, next) => {
  document.title = `${to.meta.title} - Vue Course`
  next()
})

export default router

3. 创建页面组件

src/views/HomeView.vue

<template>
  <div class="home">
    <h2>欢迎使用 Vue 3</h2>
    <p>当前计数: {{ count }}</p>
    <button @click="increment" class="btn">增加</button>
    <button @click="decrement" class="btn">减少</button>
  </div>
</template>

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

const count = ref(0)

const increment = () => count.value++
const decrement = () => count.value--
</script>

<style scoped>
.home {
  text-align: center;
  padding: 2rem;
}

.btn {
  margin: 0 0.5rem;
  padding: 0.5rem 1rem;
  border: 1px solid #ccc;
  border-radius: 4px;
  background: white;
  cursor: pointer;
}

.btn:hover {
  background: #f0f0f0;
}
</style>

状态管理

1. 安装 Pinia

npm install pinia

2. 配置 Pinia

已经在 main.ts 中配置了。

3. 创建 Store

src/stores/counter.ts

import { ref, computed } from 'vue'
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', () => {
  // 状态
  const count = ref(0)

  // 计算属性
  const doubleCount = computed(() => count.value * 2)

  // 动作
  const increment = () => {
    count.value++
  }

  const decrement = () => {
    count.value--
  }

  const reset = () => {
    count.value = 0
  }

  return {
    count,
    doubleCount,
    increment,
    decrement,
    reset
  }
})

4. 在组件中使用

<template>
  <div>
    <p>计数: {{ counter.count }}</p>
    <p>双倍: {{ counter.doubleCount }}</p>
    <button @click="counter.increment">+</button>
    <button @click="counter.decrement">-</button>
  </div>
</template>

<script setup lang="ts">
import { useCounterStore } from '@/stores/counter'

const counter = useCounterStore()
</script>

样式配置

1. 全局样式

src/assets/main.css(项目中使用的是main.css):

#app {
  max-width: 1280px;
  margin: 0 auto;
  padding: 2rem;
  font-weight: normal;
}

a,
.green {
  text-decoration: none;
  color: hsla(160, 100%, 37%, 1);
  transition: 0.4s;
}

@media (hover: hover) {
  a:hover {
    background-color: hsla(160, 100%, 37%, 0.2);
  }
}

@media (min-width: 1024px) {
  body {
    display: flex;
    place-items: center;
  }

  #app {
    display: grid;
    grid-template-columns: 1fr 1fr;
    padding: 0 2rem;
  }
}

src/assets/base.css

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  font-size: 16px;
  line-height: 1.5;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  padding: 0;
  color: #333;
  background-color: #fff;
}

h1, h2, h3, h4, h5, h6 {
  margin: 0 0 1rem 0;
  font-weight: 600;
  line-height: 1.2;
}

p {
  margin: 0 0 1rem 0;
}

a {
  color: #007acc;
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

button {
  font-family: inherit;
  border: none;
  cursor: pointer;
}

img {
  max-width: 100%;
  height: auto;
}

开发和构建

1. 开发服务器

# 启动开发服务器
npm run dev

# 或使用自定义端口
npm run dev -- --port 3000

2. 构建生产版本

# 构建生产版本
npm run build

# 预览构建结果
npm run preview

3. 代码检查

# 代码格式化
npm run format

# 代码检查
npm run lint

# 类型检查
npm run type-check

部署选项

1. 静态站点部署

Vercel

npm i -g vercel
vercel

Netlify

npm i -g netlify-cli
netlify deploy

常见问题

1. 依赖安装失败

# 清理缓存
npm cache clean --force
rm -rf node_modules package-lock.json

# 使用国内镜像
npm config set registry https://registry.npmmirror.com

# 重新安装
npm install

2. TypeScript 错误

确保 tsconfig.json 配置正确:

{
  "extends": "@vue/tsconfig/tsconfig.dom.json",
  "include": ["env.d.ts", "src/**/*", "src/**/*.vue"]
}

3. 热重载不工作

检查 Vite 配置:

export default defineConfig({
  server: {
    hmr: true
  }
})

总结

通过本教程,你已经创建了一个完整的 Vue 3 项目,包含:

  • ✅ 现代化的开发工具链
  • ✅ TypeScript 支持
  • ✅ 组件化架构
  • ✅ 状态管理
  • ✅ 路由系统
  • ✅ 代码规范
  • ✅ 静态站点部署

这个项目结构可以作为你开发 Vue 3 应用的起点。根据实际需求,你可以继续添加更多功能,如国际化、权限管理、数据可视化等。

资源链接


发布时间: 2026年1月 技术标签: Vue.js, TypeScript, Vite, 前端开发

希望这篇教程对你有帮助!如果有问题欢迎在评论区交流。

❌