vue3 + vite + ts + element-plus + env 项目基础框架手把手搭建

yarn + vue3 + vite + ts + pinia + element-plus

项目目录

在这里插入图片描述

安装vite

1. yarn create vite [选择vue + TypeScript]
2. cd project [进入项目]
3. yarn [安装依赖]
4. yarn dev [运行开发服务]

安装scss

yarn add -D scss

自动导入

  • 安装依赖
yarn add -D unplugin-vue-components unplugin-auto-import
  • 配置vite.config.ts
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";

// 自动导入vue中hook reactive ref等
import AutoImport from "unplugin-auto-import/vite";
//自动导入ui-组件 比如说ant-design-vue  element-plus等
import Components from "unplugin-vue-components/vite";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    AutoImport({
      // 安装两行后你会发现在组件中不用再导入ref,reactive等
      imports: ["vue", "vue-router"],
      // 存放的位置
      dts: "src/auto-import.d.ts",
    }),
    Components({
      // 引入组件的,包括自定义组件
      // 存放的位置
      dts: "src/components.d.ts",
    }),
  ],
});

配置@别名

  • 安装type/node支持
yarn add -D @types/node
  • 配置vite.config.ts
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";

// 1、 导入 path 模块,帮助我们解析路径
import { resolve } from "path";

// 自动导入vue中hook reactive ref等
import AutoImport from "unplugin-auto-import/vite";
//自动导入ui-组件 比如说ant-design-vue  element-plus等
import Components from "unplugin-vue-components/vite";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    AutoImport({
      // 安装两行后你会发现在组件中不用再导入ref,reactive等
      imports: ["vue", "vue-router"],
      // 存放的位置
      dts: "src/auto-import.d.ts",
    }),
    Components({
      // 引入组件的,包括自定义组件
      // 存放的位置
      dts: "src/components.d.ts",
    }),
  ],

  //1、 ↓解析配置
  resolve: {
    // ↓路径别名
    alias: {
      "@": resolve(__dirname, "./src"),
    },
  },
});
  • tsconfig.json配置baseUrl,paths参数
{
    "compilerOptions": {
        "target": "ES2020",
        "useDefineForClassFields": true,
        "module": "ESNext",
        "lib": [
            "ES2020",
            "DOM",
            "DOM.Iterable"
        ],
        "skipLibCheck": true,
        /* Bundler mode */
        "moduleResolution": "bundler",
        "allowImportingTsExtensions": true,
        "resolveJsonModule": true,
        "isolatedModules": true,
        "noEmit": true,
        "jsx": "preserve",
        /* Linting */
        "strict": true,
        "noUnusedLocals": true,
        "noUnusedParameters": true,
        "noFallthroughCasesInSwitch": true,
        // 配置@别名
        "baseUrl": "./",
        "paths": {
            "@/*": [
                "src/*"
            ]
        }
    },
    "include": [
        "src/**/*.ts",
        "src/**/*.d.ts",
        "src/**/*.tsx",
        "src/**/*.vue"
    ],
    "references": [
        {
            "path": "./tsconfig.node.json"
        }
    ]
}

vue-router

  • 安装vue-router
yarn add vue-router
  • views下新建home.vue
<template>
  <div>
    <h1>This is an Home page</h1>
  </div>
</template>
<script lang="ts">
import { defineComponent } from "vue";

export default defineComponent({
  name: "home",
});
</script>
<style scoped></style>
  • views下新建about.vue
<template>
  <div>
    <h1>This is an about page</h1>
  </div>
</template>

<script lang="ts">
export default {
  name: "about",
};
</script>

<style scoped></style>
  • router新建index.ts
import { createRouter, createWebHistory } from "vue-router";

const routes = [
  {
    path: "/",
    name: "Home",
    component: () => import("@/views/home.vue"),
  },

  {
    path: "/about",
    name: "About",
    //使用import可以路由懒加载,如果不使用,太多组件一起加载会造成白屏
    component: () => import("@/views/about.vue"),
  },
  //{
  //配置404页面
  //path: '/:catchAll(.*)',
  //name: '404',
  //component: () => import(''),
  //}
];
// 路由
const router = createRouter({
  history: createWebHistory(),
  routes,
});
// 导出
export default router;
  • main.ts引入
import { createApp } from "vue";
import "./style.css";
import App from "./App.vue";

// 1、routes
import router from "@/router/index";

const app = createApp(App);
app.use(router);
app.mount("#app");
  • App.vue中使用
<script setup lang="ts">
import HelloWorld from "./components/HelloWorld.vue";
</script>

<template>
  <div>
    <a href="https://vitejs.dev" target="_blank">
      <img src="/vite.svg" class="logo" alt="Vite logo" />
    </a>
    <a href="https://vuejs.org/" target="_blank">
      <img src="./assets/vue.svg" class="logo vue" alt="Vue logo" />
    </a>
  </div>
  <HelloWorld msg="Vite + Vue" />
  <!--    路由跳转-->
  <router-link to="/">首页</router-link>
  <br />
  <router-link to="/about">关于</router-link>
  <router-view></router-view>
</template>

<style scoped>
.logo {
  height: 6em;
  padding: 1.5em;
  will-change: filter;
  transition: filter 300ms;
}
.logo:hover {
  filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
  filter: drop-shadow(0 0 2em #42b883aa);
}
</style>

pinia

  • 安装pinia及持久化存储依赖
yarn add pinia
yarn add pinia-plugin-persistedstate
  • store下新建index.ts
import { createPinia } from "pinia";

import piniaPluginPersistedstate from "pinia-plugin-persistedstate";

const pinia = createPinia();

pinia.use(piniaPluginPersistedstate);
export default pinia;

  • 在main.ts中引入
import { createApp } from "vue";
import "./style.css";
import App from "./App.vue";

// 1、routes
import router from "@/router/index";

// 2、pinia
import pinia from "@/store";

const app = createApp(App);
app.use(router);
app.use(pinia);
app.mount("#app");

  • store下新建目录modules,并新建demo.ts
import { defineStore } from "pinia";
import { ref } from "vue";

const useDemoStore = defineStore(
  "demo",
  () => {
    const counter = ref(0);
    const increment = () => {
      counter.value++;
    };
    return {
      counter,
      increment,
    };
  }
  //   ,
  //   {
  //     // 开启持久化,默认使用localStorage
  //     persist: true,
  //   }
  //   ,
  //   {
  //     // 开启持久化,更改为sessionStorage存储
  //     persist: {
  //         storage:sessionStorage
  //     },
  //   }
);
export default useDemoStore;


  • 在about.vue中使用
<template>
  <div class="about">
    <h1>This is an about page</h1>
    <h3>counter: {{ counter }}</h3>
    <button @click="add">计数</button>
  </div>
</template>
<script setup lang="ts">
import useDemoStore from "@/store/modules/demo";

import { storeToRefs } from "pinia";

const demoStore = useDemoStore();

const { counter } = storeToRefs(demoStore);
const add = () => {
  demoStore.increment();
};
</script>
<style scoped>
button {
  color: cornflowerblue;
  font-size: 30px;
}
</style>

axios

  • 安装axios
yarn add axios
  • utils下新建request.ts
import axios from "axios";
// 创建axios实例
const request = axios.create({
  baseURL: "", // 所有的请求地址前缀部分(没有后端请求不用写)
  timeout: 80000, // 请求超时时间(毫秒)
  withCredentials: true, // 异步请求携带cookie
  // headers: {
  // 设置后端需要的传参类型
  // 'Content-Type': 'application/json',
  // 'token': x-auth-token',//一开始就要token
  // 'X-Requested-With': 'XMLHttpRequest',
  // },
});

// request拦截器
request.interceptors.request.use(
  (config) => {
    // 如果你要去localStorage获取token
    let token = localStorage.getItem("x-auth-token");
    if (token) {
      //添加请求头
      config.headers["Authorization"] = "Bearer " + token;
    }
    return config;
  },
  (error) => {
    // 对请求错误做些什么
    Promise.reject(error);
  }
);

// response 拦截器
request.interceptors.response.use(
  (response) => {
    // 对响应数据做点什么
    return response.data;
  },
  (error) => {
    // 对响应错误做点什么
    return Promise.reject(error);
  }
);
export default request;

  • api文件夹下新建login.ts
import instance from "@/utils/request";

//一般情况下,接口类型会放到一个文件
// 下面两个TS接口,表示要传的参数
interface ReqLogin {
  name: string;
  paw: string;
}

interface ReqStatus {
  id: string;
  navStatus: string;
}

// Res是返回的参数,T是泛型,需要自己定义,返回对数统一管理***
type Res<T> = Promise<ItypeAPI<T>>;
// 一般情况下响应数据返回的这三个参数,
// 但不排除后端返回其它的可能性,
interface ItypeAPI<T> {
  data: T; //请求的数据,用泛型
  msg: string | null; // 返回状态码的信息,如请求成功等
  code: number; //返回后端自定义的200,404,500这种状态码
}

// post请求 ,没参数
export const LogoutAPI = (): Res<null> => instance.post("/admin/logout");

// post请求,有参数,如传用户名和密码
export const loginAPI = (data: ReqLogin): Res<string> =>
  instance.post("/admin/login", data);

// post请求 ,没参数,但要路径传参
export const StatusAPI = (data: ReqStatus): Res<null> =>
  instance.post(`/productCategory?ids=${data.id}&navStatus=${data.navStatus}`);

//  get请求,没参数,
export const FlashSessionListApi = (): Res<null> =>
  instance.get("/flashSession/list");

// get请求,有参数,路径也要传参  (也可能直接在这写类型,不过不建议,大点的项目会维护一麻烦)
export const ProductCategoryApi = (params: { parentId: number }): Res<any> =>
  instance.get(`/productCategory/list/${params.parentId}`, { params });

// get请求,有参数,(如果你不会写类型也可以使用any,不过不建议,因为用了之后 和没写TS一样)
export const AdminListAPI = (params: any): Res<any> =>
  instance.get("/admin/list", { params });

  • 第一种使用方式:使用.then
<script setup lang="ts">
import {loginAPI} from "@/api/login";

const login= () => {
    loginAPI({
        ...val,
    }).then((res) => {
        console.log('***',res );
        let { list, pageNum, pageSize, total } = res.data
    })

};
</script>

  • 第二种使用方式:直接使用(和vue2在cretae上用一样,setup自带async,await在顶层可以直接使用)
<script setup lang="ts">
import { loginAPI} from "@/api/login";
    //直接使用,一般用在进入页面入请求数据的接口
    let res = await loginAPI()
    console.log( "***" ,res);
}
</script>

  • 第三种使用方式:使用async/await,(setup虽然自带async,但单独用await只能在顶层使用,如果在函数下还是要async/await一起写)
<script setup lang="ts">
import { loginAPI} from "@/api/login";
 
const search = async(val: IUseTableParam) => {
    let res = await loginAPI({
        ...val,
    })
    console.log( "***" ,res);
    let { list, pageNum, pageSize, total } = res.data
    console.log(list, pageNum, pageSize, total);
}
</script>

element-plus

  • 安装element-plus
yarn add element-plus
  • vite.config.ts配置
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";

// 1、 导入 path 模块,帮助我们解析路径
import { resolve } from "path";

// 自动导入vue中hook reactive ref等
import AutoImport from "unplugin-auto-import/vite";
// 自动导入ui-组件 比如说ant-design-vue  element-plus等
import Components from "unplugin-vue-components/vite";

// 自动导入element-plus
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    AutoImport({
      // 安装两行后你会发现在组件中不用再导入ref,reactive等
      imports: ["vue", "vue-router"],
      // 存放的位置
      dts: "src/auto-import.d.ts",
      resolvers: [ElementPlusResolver()],
    }),
    Components({
      // 引入组件的,包括自定义组件
      // 存放的位置
      dts: "src/components.d.ts",
      resolvers: [ElementPlusResolver()],
    }),
  ],

  //1、 ↓解析配置
  resolve: {
    // ↓路径别名
    alias: {
      "@": resolve(__dirname, "./src"),
    },
  },
});

  • about.vue中使用
<template>
  <div class="about">
    <h1>This is an about page</h1>
    <h3>counter: {{ counter }}</h3>
    <el-button type="primary" @click="add">计数</el-button>
  </div>
</template>
<script setup lang="ts">
import useDemoStore from "@/store/modules/demo";

import { storeToRefs } from "pinia";

const demoStore = useDemoStore();

const { counter } = storeToRefs(demoStore);
const add = () => {
  demoStore.increment();
};
</script>
<style scoped></style>

element-plus 自动导入图标

  • 安装unplugin-icons
yarn add -D unplugin-icons
  • vite.config.ts配置
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";

// 1、 导入 path 模块,帮助我们解析路径
import { resolve } from "path";

// 自动导入vue中hook reactive ref等
import AutoImport from "unplugin-auto-import/vite";
// 自动导入ui-组件 比如说ant-design-vue  element-plus等
import Components from "unplugin-vue-components/vite";

// 自动导入element-plus
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";

// 自动导入element-plus图标
import Icons from "unplugin-icons/vite";
import IconsResolver from "unplugin-icons/resolver";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    AutoImport({
      // 安装两行后你会发现在组件中不用再导入ref,reactive等
      imports: ["vue", "vue-router"],
      // 存放的位置
      dts: "src/auto-import.d.ts",
      resolvers: [
        ElementPlusResolver(),

        // 自动导入图标组件
        IconsResolver({
          prefix: "Icon",
        }),
      ],
    }),
    Components({
      // 引入组件的,包括自定义组件
      // 存放的位置
      dts: "src/components.d.ts",
      resolvers: [
        // 自动注册图标组件
        IconsResolver({
          enabledCollections: ["ep"],
        }),

        ElementPlusResolver(),
      ],
    }),
    // 自动导入图标组件
    Icons({
      autoInstall: true,
    }),
  ],

  //1、 ↓解析配置
  resolve: {
    // ↓路径别名
    alias: {
      "@": resolve(__dirname, "./src"),
    },
  },
});

  • about.vue中使用
<template>
  <div class="about">
    <h1>This is an about page</h1>
    <h3>counter: {{ counter }}</h3>
    <el-button type="primary" @click="add">计数</el-button>

    <i-ep-edit />
    <el-icon :size="30">
      <i-ep-edit></i-ep-edit>
    </el-icon>
  </div>
</template>
<script setup lang="ts">
import useDemoStore from "@/store/modules/demo";

import { storeToRefs } from "pinia";

const demoStore = useDemoStore();

const { counter } = storeToRefs(demoStore);
const add = () => {
  demoStore.increment();
};
</script>
<style scoped></style>

element-plus 自动导入中文

  • vite-env.d.ts注册中文模块
/// <reference types="vite/client" />

// 注册element-plus中文模块
declare module "element-plus/dist/locale/zh-cn.mjs";

  • App.vue使用
<script setup lang="ts">
import HelloWorld from "./components/HelloWorld.vue";
// 引入element-plus中文包
import zhCn from "element-plus/dist/locale/zh-cn.mjs";
</script>

<template>
  <div>
    <a href="https://vitejs.dev" target="_blank">
      <img src="/vite.svg" class="logo" alt="Vite logo" />
    </a>
    <a href="https://vuejs.org/" target="_blank">
      <img src="./assets/vue.svg" class="logo vue" alt="Vue logo" />
    </a>
  </div>
  <HelloWorld msg="Vite + Vue" />
  
  <!-- 路由跳转 -->
  <router-link to="/">首页</router-link>
  <br />
  <router-link to="/about">关于</router-link>

  <!-- element-plus 中文 -->
  <el-config-provider :locale="zhCn">
    <!-- 添加路由组件 -->
    <router-view />
  </el-config-provider>
</template>

<style scoped>
.logo {
  height: 6em;
  padding: 1.5em;
  will-change: filter;
  transition: filter 300ms;
}
.logo:hover {
  filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
  filter: drop-shadow(0 0 2em #42b883aa);
}
</style>

多项目环境配置

  • 安装依赖:cross-env dotenv fs
yarn add -D cross-env dotenv fs
  • 根目录下新建三个项目配置文件env
--------------.env文件-----------------
# 基础路径
VITE_BASE_URL = './'

NODE_ENV = local

# 输出目录
# VITE_OUTPUT_DIR = 'dist_local'
# 本地接口路径
VITE_API_DOMAIN = 'http://127.0.0.1:8000'

--------------.env.develop文件-----------------
NODE_ENV = develop

# 输出目录
VITE_OUTPUT_DIR = 'dist_develop'
# 测试环境地址
VITE_API_DOMAIN = 'http://my-admin-laravel7.me'


--------------.env.production文件-----------------
NODE_ENV = production

# 输出目录
VITE_OUTPUT_DIR = 'dist_production'
# 正式环境地址
VITE_API_DOMAIN = 'http://my-admin-laravel7.me'

  • vite.config.ts改造
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";

// 1、 导入 path 模块,帮助我们解析路径
import { resolve } from "path";

// 自动导入vue中hook reactive ref等
import AutoImport from "unplugin-auto-import/vite";
// 自动导入ui-组件 比如说ant-design-vue  element-plus等
import Components from "unplugin-vue-components/vite";

// 自动导入element-plus
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";

// 自动导入element-plus图标
import Icons from "unplugin-icons/vite";
import IconsResolver from "unplugin-icons/resolver";

// 多环境
import dotenv from "dotenv";
import fs from "fs";

// https://vitejs.dev/config/
export default ({ command, mode }) => {
  // 根据不同的环境使用不同的环境变量
  let envFiles: string[] = [];
  if (command === "serve") {
    envFiles = [
      /** default file */
      `.env`,
    ];
  } else {
    envFiles = [
      /** default file */
      `.env`,
      /** mode file */
      `.env.${mode}`,
    ];
  }
  for (const file of envFiles) {
    const envConfig = dotenv.parse(fs.readFileSync(file));
    // eslint-disable-next-line guard-for-in
    for (const k in envConfig) {
      process.env[k] = envConfig[k];
    }
  }

  return defineConfig({
    // base: process.env.VITE_BASE_URL,
    plugins: [
      vue(),
      AutoImport({
        // 安装两行后你会发现在组件中不用再导入ref,reactive等
        imports: ["vue", "vue-router"],
        // 存放的位置
        dts: "src/auto-import.d.ts",
        resolvers: [
          ElementPlusResolver(),

          // 自动导入图标组件
          IconsResolver({
            prefix: "Icon",
          }),
        ],
      }),
      Components({
        // 引入组件的,包括自定义组件
        // 存放的位置
        dts: "src/components.d.ts",
        resolvers: [
          // 自动注册图标组件
          IconsResolver({
            enabledCollections: ["ep"],
          }),

          ElementPlusResolver(),
        ],
      }),
      // 自动导入图标组件
      Icons({
        autoInstall: true,
      }),
    ],

    // 1、 ↓解析配置
    resolve: {
      // ↓路径别名
      alias: {
        "@": resolve(__dirname, "./src"),
      },
    },
    // 构建
    build: {
      outDir: process.env.VITE_OUTPUT_DIR,
    },
    define: {
      "process.env": {},
    },
    // server: {
    //   host: process.env.VITE_HOST,
    //   port: Number(process.env.VITE_PORT),
    //   open: false, // 设置服务启动时是否自动打开浏览器
    //   https: false, // 是否开启 https
    //   cors: true, // 允许跨域

    //   // 设置代理,根据我们项目实际情况配置
    //   proxy: {
    //     "/api": {
    //       target: process.env.VITE_API_DOMAIN,
    //       changeOrigin: true,
    //       secure: false,
    //       rewrite: (path) => path.replace("/api/", "/"),
    //     },
    //   },
    // },
  });
};

  • package.json修改命令
{
    "name": "vue3-vite-ts-yarn",
    "private": true,
    "version": "0.0.0",
    "type": "module",
    "scripts": {
        "dev": "vite",
        // 修改构建命令增加参数
        "build:dev": "vue-tsc --noEmit && cross-env vite build --mode develop",
        "build:prod": "vue-tsc --noEmit && cross-env  vite build --mode production",
        "preview": "vite preview"
    },
    "dependencies": {
        "axios": "^1.5.0",
        "element-plus": "^2.3.14",
        "pinia": "^2.1.6",
        "pinia-plugin-persistedstate": "^3.2.0",
        "vue": "^3.3.4",
        "vue-router": "^4.2.4"
    },
    "devDependencies": {
        "@iconify-json/ep": "^1.1.12",
        "@types/node": "^20.6.3",
        "@vitejs/plugin-vue": "^4.2.3",
        "cross-env": "^7.0.3",
        "dotenv": "^16.3.1",
        "fs": "^0.0.1-security",
        "scss": "^0.2.4",
        "typescript": "^5.0.2",
        "unplugin-auto-import": "^0.16.6",
        "unplugin-icons": "^0.17.0",
        "unplugin-vue-components": "^0.25.2",
        "vite": "^4.4.5",
        "vue-tsc": "^1.8.5"
    }
}

打包后假设到nginx后,在/about页面刷新报错解决

  • nginx配置文件增加
location / {
  try_files $uri $uri/ /index.html; #解决页面刷新404问题
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值