vue3项目搭建

Marimo_z
2025-03-31 / 0 评论 / 19 阅读 / 正在检测是否收录...
vue3 vite + js项目搭建全流程(axios,router,pinia,echarts,sass,element-plus部署)
Gitee仓库:示例代码

一、项目初始化

npm create vite@latest my-vue-project -- --template vue
cd my-vue-project
npm install

二、依赖安装

npm install axios
npm install vue-router@4
npm install pinia
npm install pinia pinia-plugin-persistedstate
npm install -D sass-embedded
npm install echarts --save
npm install element-plus --save
npm install @element-plus/icons-vue
  • main.js 中挂载
import { createApp } from 'vue'
import App from './App.vue'

/* 全局样式 */
import './style.css'

/* 字体 */
import '@/assets/fonts/font.css';

/* 路由 */
import router from './router'

/* 状态管理 */
import { createPinia } from 'pinia'
/* pinia持久化存储 */
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'

/* ElementPlus */
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
/* ElementPlus-图标 */
import * as ElementPlusIconsVue from '@element-plus/icons-vue'

const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
const app = createApp(App)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
    app.component(key, component)
}
app.use(pinia)
app.use(router)
app.use(ElementPlus)
app.mount('#app')

三、项目结构建议

# 项目根目录
public/             # 静态资源目录(不会被 webpack 处理,直接复制到打包目录)
  ├── favicon.ico   # 网站图标文件

src/                # 主开发目录
├── api/            # API 请求模块目录(存放所有接口请求文件)
├── assets/         # 静态资源目录(会被 webpack 处理)
│   ├── fonts/      # 字体文件目录
│   │   ├── font.css  # 字体样式定义文件
│   │   └── typeface.ttf  # 字体文件
│   ├── icons/      # SVG 图标资源目录
│   ├── images/     # 图片资源目录
│   ├── logo/       # 网站 LOGO 文件目录
│   ├── music/      # 音频文件目录
│   └── styles/     # 全局样式文件目录(可存放 scss/less/css 文件)
│
├── components/     # 公共组件目录(可复用的 Vue 组件)
├── router/         # 路由配置目录(Vue Router 配置文件)
├── stores/         # 状态管理目录(Pinia/Vuex 状态管理配置)
├── utils/          # 工具函数目录(公共方法、工具类文件)
├── views/          # 页面视图目录(路由页面组件)
│   ├── 404/        # 404 页面目录
│   │   └── index.vue
│   ├── home/       # 首页目录
│   │   └── index.vue
│   ├── index.vue   # 默认入口页面
│   └── login.vue   # 登录页面组件
│
├── App.vue         # Vue 应用根组件
└── main.js         # 应用入口文件(初始化 Vue 实例)

# 环境变量文件
.env.development    # 开发环境变量配置(本地开发使用)
.env.production     # 生产环境变量配置(正式部署使用)

四、环境变量

  1. 开发环境配置 .env.development

    # 页面标题
    VITE_APP_TITLE = 个人网页
    
    # 开发环境配置
    VITE_APP_ENV = 'development'
    
    # 开发环境地址
    VITE_APP_BASE_API = '/dev-api'
    
    # websocket 开关 默认使用sse推送
    VITE_APP_WEBSOCKET = false
  2. 生产环境配置 .env.production

    # 页面标题
    VITE_APP_TITLE = 个人网页
    
    # 生产环境配置
    VITE_APP_ENV = 'production'
    
    # 生产环境地址
    VITE_APP_BASE_API = '/prod-api'
    
    # websocket 开关 默认使用sse推送
    VITE_APP_WEBSOCKET = false

五、重构核心配置

  • 配置路径别名&跨域处理 vite.config.js
import { defineConfig, loadEnv } from 'vite';
import vue from '@vitejs/plugin-vue'
import path from 'path' // 引入 path 模块

export default defineConfig(({ mode }) => {
  // 加载环境变量
  const env = loadEnv(mode, process.cwd(), '');

  return {
    plugins: [vue()],
    resolve: {
      alias: {
        '~': path.resolve(__dirname, './'),
        '@': path.resolve(__dirname, './src') // 将 @ 指向 src 目录
      },
      extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
    },
    server: {
      host: '0.0.0.0', // 监听所有可用网络接口
      open: true, // 启动开发服务器时自动打开默认浏览器
      proxy: {
        [env.VITE_APP_BASE_API]: {
          target: 'http://localhost:8080', // 后端地址
          changeOrigin: true,
          ws: true, // 启用 WebSocket 代理
          rewrite: (path) => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), ''),
          secure: false // 如果使用 HTTPS 需要设为 true
        }
      }
    }
  }
})

六、基础文件配置

  1. 清除全局边距 index.html

    * {
        padding: 0;
        margin: 0;
    }
  2. 设置路由出口 App.vue

    <template>
      <div id="app">
        <!-- 路由出口 -->
        <router-view />
      </div>
    </template>
    
    <style scoped>
    * {
      margin: 0;
      padding: 0;
    }
    </style>
  3. 首页配置 views/index.vue

    <template>
        <div class="common-layout">
            <el-container>
                <!-- 导航栏 -->
                <el-header>
                    <el-menu :default-active="$route.path" class="el-menu-demo" mode="horizontal" :ellipsis="false" router>
                        <el-menu-item index="/">HOME</el-menu-item>
                        <el-menu-item index="/404">404</el-menu-item>
                    </el-menu>
                </el-header>
    
                <!-- 主体 -->
                <el-main>
                    <RouterView />
                </el-main>
            </el-container>
        </div>
    </template>
    
    <script setup></script>
    
    <style lang="scss" scoped>
        .el-header,
        .el-main {
            margin: 0;
            padding: 0;
        }
    
        .el-main {
            height: calc(100vh - 60px);
            overflow: hidden;
            position: relative;
        }
    
        .common-layout {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100vh;
            box-sizing: border-box;
            /* 固定页面 */
            position: fixed;
        }
    </style>

七、Vue Router 配置

  1. 创建路由管理文件 src/router/index.js

    import { createRouter, createWebHistory } from "vue-router";
    import { constantRoute } from "./routes";
    
    const router = createRouter({
        history: createWebHistory(import.meta.env.BASE_URL),
        routes: constantRoute,
        // 滚动行为
        scrollBehavior() {
            return {
                left: 0,
                top: 0
            }
        }
    });
    
    export default router;
  2. 创建路由文件 src/router/routes.js

    // 对外暴露配置路由(常量路由)
    
    export const constantRoute = [
        {
            // 主页
            path: "/",
            name: "home",
            component: () => import("@/views/index.vue"),
            children: [
                {
                    path: '/home',
                    redirect: '/' // 重定向到默认子路由
                },
                {
                    path: '',     // 首页(默认)
                    name: 'HOME',
                    component: () => import("@/views/home/index.vue")
                }
            ]
        },
        {
            // 404
            path: "/404",
            name: "404",
            component: () => import("@/views/404/index.vue"),
        },
        {
            // 任意路由(若进入未知路由则跳转该路由)
            path: "/:pathMatch(.*)*",
            name: "Any",
            redirect: "/404",
        },
    ];

八、Pinia 状态管理

  1. 创建 store 实例 src/stores/user.js

    import { defineStore } from 'pinia'
    
    /* 示例 用户数据存储 */
    export const useUserStore = defineStore('user', {
      state: () => ({
        token: '',
        username: 'Guest',
        isLoggedIn: false
      }),
      actions: {
        login(token, username) {
          this.token = token
          this.username = username
          this.isLoggedIn = true
        },
        logout() {
          this.token = ''
          this.username = 'Guest'
          this.isLoggedIn = false
        }
      },
      persist: {
        enabled: true, // 开启持久化
        strategies: [
          {
            key: 'userData', // 自定义存储 key(默认使用 store id)
            storage: localStorage, // 指定存储方式(默认 sessionStorage)
            paths: ['token', 'isLoggedIn'] // 仅持久化 token 和 isLoggedIn
          }
        ]
      }
    })
  2. 在 Vue 组件中操作 Store

    <script setup>
    import { useUserStore } from '@/stores/user'
    import { storeToRefs } from 'pinia'
    
    const userStore = useUserStore()
    const { token, username, isLoggedIn } = storeToRefs(userStore) // 使用 storeToRefs 保持响应性
    
    const handleLogin = () => {
      userStore.login('abc123', 'JohnDoe') // 调用 Action
    }
    
    const handleLogout = () => {
      userStore.logout()
    }
    </script>
    
    <template>
      <div v-if="isLoggedIn">
        <p>Welcome, {{ username }} (Token: {{ token }})</p>
        <button @click="handleLogout">Logout</button>
      </div>
      <div v-else>
        <button @click="handleLogin">Login</button>
      </div>
    </template>

九、Axios 封装

  1. 创建拦截器 src/utils/request.js

    import axios from "axios";
    
    // 创建 axios 实例
    const service = axios.create({
      baseURL: import.meta.env.VITE_APP_BASE_API, // 通过环境变量配置
      timeout: 50000,
      headers: { "Content-Type": "application/json" }
    });
    
    // 请求拦截器
    service.interceptors.request.use(
      config => {
        // 携带 Token 的逻辑(示例)
        const token = localStorage.getItem("access_token");
        if (token) {
          config.headers.Authorization = `Bearer ${token}`;
        }
        return config;
      },
      error => Promise.reject(error)
    );
    
    // 响应拦截器
    service.interceptors.response.use(
      response => {
        // 处理 2xx 状态码
        const { code, message } = response.data;
        if (code === 200) {
          return response.data; // 直接返回核心数据
        } else {
          return Promise.reject(new Error(message || "请求异常"));
        }
      },
      error => {
        // 处理非 2xx 状态码
        const status = error.response?.status;
        switch (status) {
          case 401:
            console.error("登录过期,请重新登录");
            router.replace("/login");
            break;
          case 403:
            console.error("没有权限访问");
            break;
          case 500:
            console.error("服务器内部错误");
            break;
          default:
            console.error("网络异常,请稍后重试");
        }
        return Promise.reject(error);
      }
    );
    
    export default service;
  2. 创建请求src/api/user/index.js

    import request from "@/utils/request";
    
    // 示例:获取用户信息
    export const getUserInfo = () => {
      return request({
        url: '/user/getUserInfo',
        method: 'get',
      });
    };

十、外部字体引入

/* 
 * src/assets/fonts/font.css
 * ttf字体文件放在同级目录下 './'
 *
 * font-family - 自定义字体名称
 * src - 字体路径
 * font-weight - 字体粗细
 * font-style - 字体样式
 */

/* 字体引入 */
@font-face {
    font-family: 'Typeface';
    src: url('./typeface.ttf') format('truetype');
    font-weight: normal;
    font-style: normal;
}

十一、项目指令

# 运行项目
npm run dev

# 打包项目
npm run build
8

评论 (0)

取消