1、前端框架:Vue3.x
2、构建工具:Vite2.x
3、编程语言:TypeScript
4、状态管理工具:Pinia
5、路由管理工具:Vue Router
6、前端UI框架:Ant Design Vue
7、Http请求工具:Axios
8、CSS处理器:Less/Scss/Stylus
...
├─ public
├─ src
│ ├─ api // 用于存储项目所有的api,可根据模块添加多个文件夹以区分
│ ├─ asseets // 用于存储项目所有的静态资源
│ ├─ components // 用于存储所有的公共组件,可根据模块新建对应的文件夹以区分
│ ├─ plugins // 用于存储项目所有的插件或工具函数(就是通常所说的utils文件夹,这里我起的名叫plugins)
│ ├─ router // 用于项目路由配置
│ ├─ store // 用于项目全局状态管理配置
│ ├─ views // 用于项目页面目录
│ ├─ App.vue // 项目根文件
│ ├─ env.d.ts
│ ├─ main.ts // 项目配置入口文件
├─ .gitignore
├─ index.html
├─ package-lock.json
├─ package.json
├─ tsconfig.json // TypeScript 配置文件
├─ tsconfig.node.json
├─ vite.config.ts // Vite 配置文件
...
1、安装vite环境
npm init @vitejs/app
或
yarn create @vitejs/app
2、初始化项目
npm init @vitejs/app project-name
或
yarn create @vitejs/app project-name
【注:终端里需要填的内容】
project-name 项目的名字
select-a-framework 所需要使用的技术栈
select-a-variant 所需要使用的语言类型
~~如此一来,以上,项目初始化已经完成!
接下来就可以在终端执行npm install来安装依赖,安装完成后项目就创建完成了,执行npm run dev,项目启动。
3、修改配置
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
// 如果编辑器提示 path 模块找不到,则可以安装一下 @types/node -> npm i @types/node -D
import { resolve } from 'path';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': resolve(__dirname, 'src') // 设置 `@` 指向 `src` 目录
}
},
base: './', // 设置打包路径
server: {
port: 4000, // 设置服务启动端口号
open: true, // 设置服务启动时是否自动打开浏览器
cors: true // 允许跨域
// 设置代理,根据我们项目实际情况配置
// proxy: {
// '/api': {
// target: 'http://xxx.xxx.xxx.xxx:8000',
// changeOrigin: true,
// secure: false,
// rewrite: (path) => path.replace('/api/', '/')
// }
// }
}
})
path模块是node中的一个核心模块,需要安装让 TypeScript 支持 node.js 的依赖包。
如果编辑器提示 path 模块找不到,则可以安装一下 @types/node。命令如下:
npm install @types/node -D
{
"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,
"paths": {
"@/*":[
"./src/*"
]
}
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
"references": [{ "path": "./tsconfig.node.json" }]
}
npm install vue-router@4
或
yarn add vue-router@4
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
import Home from '@/views/home.vue';
const routes: Array<RouteRecordRaw> = [
{
path: '/',
name: 'Home',
component: Home
},
// 懒加载组件写法
{
path: "/home",
name: "home",
component: () => import("../views/home.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>
<Home></Home>
</template>
<script setup lang="ts">
import Home from '@/views/home.vue'
</script>
<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>
npm install pinia@next
或
yarn install pinia@next
import { defineStore } from "pinia";
// id 必须保证唯一性; 两种写法:
// export const piniaStore = defineStore("userId", {})
// export const piniaStore = defineStore({id: "userId", })
export const piniaStore = defineStore("userId", {
// 必须是箭头函数: 为了在服务器端渲染的时候避免交叉请求导致数据状态污染
state: () => {
return {
count: 0,
count2: 2,
};
},
getters: {
getNum(state) {
return state.count;
},
getNum2(state) {
return state.count2;
},
},
actions: {
updateCount() {
this.count++;
},
updateCount2(data: number) {
this.count2 = data;
},
},
});
import { createApp } from "vue";
import router from "./router";
import App from "./App.vue";
import { createPinia } from "pinia";
const app = createApp(App);
const pinia = createPinia();
app.use(router);
app.use(pinia);
app.mount("#app");
<template>
<div>
欢迎来到home页
<h1>{{piniaStore.getNum}}</h1>
<h1>{{piniaStore.getNum2}}</h1>
<button @click="changedCount">click</button>
<button @click="changedCount2">click2</button>
</template>
<script lang="ts">
import piniaStore from '@/store';
export default {
setup(){
const piniaStore = piniaStore()
return{
piniaStore
}
},
methods:{
changedCount(){
this.piniaStore.updateCount()
},
changedCount2(){
this.piniaStore.updateCount2(3)
}
}
}
</script>
npm install axios
或
yarn add axios
import axios from "axios";
let baseURL = "";
if (import.meta.env.MODE == "development") {
baseURL = "/api";
} else {
baseURL = "/prod";
}
const service = axios.create({
baseURL: baseURL,
});
// 请求拦截器
service.interceptors.request.use(
(config) => {
// do something before request is sent
// if (!getToken() && config.url.indexOf("login") == -1) {
// location.reload()
// }
return config;
},
(error) => {
// do something with request error
console.log(error); // for debug
return Promise.reject(error);
}
);
// 响应拦截器
// response interceptor
service.interceptors.response.use(
(response) => {
return response;
},
(error) => {
console.log("err" + error); // for debug
return Promise.reject(error);
}
);
export default service;
import request from "@/plugins/axios";
type common = Promise<any>;
// 例子
export function getHostRecoveryDataList(): common {
return request({
url: "/api/recovery/hostRecovery/list",
method: "get",
});
}
npm install ant-design-vue@next --save
或
yarn add ant-design-vue@next
import { createApp } from "vue";
import router from "./router";
import App from "./App.vue";
import { createPinia } from "pinia";
import Antd from "ant-design-vue";
import "ant-design-vue/dist/antd.css";
const app = createApp(App);
const pinia = createPinia();
app.use(router);
app.use(pinia);
app.use(Antd);
app.mount("#app");
<template>
<div>
<!-- 欢迎来到home页
<button @click="changedCount">click</button>
<button @click="changedCount2">click2</button> -->
<a-layout class="wrapper">
<a-layout-sider v-model:collapsed="collapsed" :trigger="null" collapsible>
<div class="logo">LOGO</div>
<a-menu v-model:selectedKeys="selectedKeys" theme="dark" mode="inline">
<a-menu-item key="1">
<user-outlined />
<span>nav 1</span>
</a-menu-item>
<a-menu-item key="2">
<video-camera-outlined />
<span>nav 2</span>
</a-menu-item>
<a-menu-item key="3">
<upload-outlined />
<span>nav 3</span>
</a-menu-item>
</a-menu>
</a-layout-sider>
<a-layout>
<a-layout-header style="background: #fff; padding: 0">
<menu-unfold-outlined
v-if="collapsed"
class="trigger"
@click="() => (collapsed = !collapsed)"
/>
<menu-fold-outlined v-else class="trigger" @click="() => (collapsed = !collapsed)" />
</a-layout-header>
<a-layout-content
:style="{ margin: '24px 16px', padding: '24px', background: '#fff', minHeight: '280px' }"
>
Content
</a-layout-content>
</a-layout>
</a-layout>
</div>
</template>
<script lang="ts">
import {
UserOutlined,
VideoCameraOutlined,
UploadOutlined,
MenuUnfoldOutlined,
MenuFoldOutlined,
} from '@ant-design/icons-vue';
import { defineComponent, ref } from 'vue';
export default defineComponent({
components: {
UserOutlined,
VideoCameraOutlined,
UploadOutlined,
MenuUnfoldOutlined,
MenuFoldOutlined,
},
setup() {
return {
selectedKeys: ref<string[]>(['1']),
collapsed: ref<boolean>(false),
};
}
})
</script>
<style lang="less" scoped>
.wrapper {
width: 100%;
height: 100vh;
min-height: 100vh;
background-color: pink;
display: flex;
}
.logo{
height: 32px;
background: rgba(255, 255, 255, 0.3);
margin: 16px;
color: #FFF;
text-align: center;
padding-top: 5px;
}
/deep/ .ant-layout-header{
padding-left: 20px !important;
}
</style>
npm i less -D
或
npm i sass -D
或
npm i stylus -D
<style lang="less" scoped>
.wrapper {
width: 100%;
height: 100vh;
min-height: 100vh;
background-color: pink;
display: flex;
}
</style>
完结,撒花✿✿ヽ(°▽°)ノ✿
~欢迎小伙伴留言指教哦!!!