// 使用 npm
npm init vite@latest vue3-ts-frontend --template vue-ts
// 使用 yarn
yarn create vite vue3-ts-frontend --template vue-ts
npm install ant-design-vue -S
npm install vue-router -S
npm install vue-i18n -S
npm install pinia -S
npm install axios -S
tsconfig.json
, 新增compilerOptions.baseUrl
、compilerOptions.paths
{
"compilerOptions": {
"target": "esnext",
"useDefineForClassFields": true,
"module": "esnext",
"moduleResolution": "node",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"isolatedModules": true,
"esModuleInterop": true,
"lib": ["esnext", "dom"],
"skipLibCheck": true,
"baseUrl": "./", // 新增
"paths": { // 新增
"@": ["./src"],
"@/*": ["./src/*"],
}
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }]
}
vite.config.ts
, 新增resolve.alias
、server
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: 8080, //启动端口
hmr: {
host: '127.0.0.1',
port: 8080,
},
// 设置 https 代理
proxy: {
'/api': {
target: 'http://localhost:3000', // 后端 api 地址
changeOrigin: true,
rewrite: (path: string) => path.replace(/^\/api/, ''),
},
},
},
});
在 main.ts 中引入并使用
import { createApp } from 'vue';
import Antd from 'ant-design-vue';
import App from './App.vue';
import 'ant-design-vue/dist/antd.css';
const app = createApp(App);
app.use(Antd);
app.mount('#app');
router/index.ts
文件import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router';
const routes: Array<RouteRecordRaw> = [
{
path: '/login',
name: 'login',
meta: {
title: '登录',
keepAlive: true,
requireAuth: false
},
component: () => import('@/pages/login/index.vue'),
},
{
path: '/',
name: 'home',
meta: {
title: '首页',
keepAlive: true,
requireAuth: true
},
component: () => import('@/pages/home/index.vue'),
},
];
const router = createRouter({
history: createWebHistory(),
routes,
});
export default router;
import { createApp } from 'vue';
import App from './App.vue';
import router from '@/router';
const app = createApp(App);
app.use(router);
app.mount('#app');
<template>
<div id="app">
<router-view />
</div>
</template>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
locales/index.ts
、locales/zh-CN.ts
、locales/en-US.ts
文件index.ts
import { createI18n } from 'vue-i18n/index';
import zh from './zh-CN';
import en from './en-US';
const defaultLanguage = 'zh-CN';
const i18n = createI18n({
locale: defaultLanguage,
silentTranslationWarn: true,
messages: { zh, en },
});
export default i18n;
zh-CN.ts
export default {
home: {
title: '首页',
test: '测试',
},
};
en-US.ts
export default {
home: {
title: 'Home',
test: 'Test',
},
};
import { createApp } from 'vue';
import App from './App.vue';
import i18n from '@/locales';
const app = createApp(App);
app.use(i18n);
app.mount('#app');
<template>
<div>
<h1 v-text="$t('home.title')" />
<div v-text="test" />
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const test = ref(t('home.test'));
</script>
store/index.ts
、store/user.ts
文件index.ts
import { createPinia } from 'pinia';
const store = createPinia();
export default store;
user.ts
import { defineStore } from 'pinia';
export const useUserStore = defineStore({
id: 'user', // 必填且唯一
state: () => {
return {
name: 'TFBoys',
};
},
actions: {
updateName(name: string) {
this.name = name;
},
},
});
import { createApp } from 'vue';
import App from './App.vue';
import store from './store';
const app = createApp(App);
app.use(store);
app.mount('#app');
<template>
<div>
<div v-text="userStore.name" />
<a-button v-text="$t('home.updateState')" @click="onUpdateName" />
</div>
</template>
<script setup lang="ts">
import { useUserStore } from '@/store/user';
const userStore = useUserStore();
const onUpdateName = () => {
// 通过 actions 去修改 state
userStore.updateName('杨洋');
}
</script>
utils/request.ts
文件import axios, { AxiosResponse, AxiosRequestConfig } from 'axios';
const service = axios.create({
// baseURL: 'http://localhost:3000',
withCredentials: true,
});
// Request interceptors
service.interceptors.request.use(
(config: AxiosRequestConfig) => {
// do something
return config;
},
(error: any) => {
Promise.reject(error);
}
);
// Response interceptors
service.interceptors.response.use(
async (response: AxiosResponse) => {
// do something
return response.data;
},
(error: any) => {
// do something
return Promise.reject(error);
}
);
export default service;
engine/index.ts
、engine/Users.ts
文件index.ts
import Users from './Users';
export {
Users,
};
Users.ts
import request from '@/utils/request';
export default class Users {
static fetchAll = () => request.get(`/api/users/list`);
};
<template>
<div>
<div v-for="user in userList" :key="user.id">
{{ user.username }}
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { Users } from '@/engine';
const userList = ref([]);
const init = async() => {
const { data } = await Users.fetchAll();
userList.value = data;
};
init();
</script>