Front-end project construction - vite+vue3.0+ant
vite is faster than webpack
vite build project
https://cn.vitejs.dev/
Steps:
1. Open cmd
2. Find the folder where the project should be built
, such as building it directly on the desktop
cd desktop
3. Create a project
Use the create project command, then fill in the project name according to the prompts, and the technology to be used, vue and ts, then you will see the project on the desktop
npm create vite@latest
4. Then find the newly created project, download dependencies, and start the project
npm install //下载依赖
npm run dev //启动项目
Running effect:
After that, we can use the packaging command, and we can see that a dist package will be generated. At this point the project is built.
npm run build
You can delete files like components and useless things in App.vue
Configuration file -vite.config.js
import {
defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import {
resolve } from "path";
// https://vitejs.dev/config/
export default defineConfig({
base: './',
plugins: [vue()],
resolve: {
alias: {
'@': resolve(__dirname, 'src'),
"@c": resolve(__dirname, "src/components"),
"@view": resolve(__dirname, "src/view"),
"@assets": resolve(__dirname, "src/assets"),
},
extensions: ['.js', '.jsx', '.json'], // 导入时想要忽略的扩展名列表
preserveSymlinks: false, // 启用此选项会使 Vite 通过原始文件路径确定文件身份
},
server: {
// 配置反向代理
host: '0.0.0.0', // 启动后浏览器窗口输入地址就可以进行访问
port: 8001, // 端口号
open: true, //是否自动打开浏览器
cors: true, //为开发服务器配置 CORS , 默认启用并允许任何源
https: false, //是否支持http2 如果配置成true 会打开https://localhost:3001/xxx;
strictPort: true, //是否是严格的端口号,如果true,端口号被占用的情况下,vite会退出
hmr: true, // 开启热更新
// proxy: {
// '/api': {
// // 配置接口调用目标地址
// target: 'https://www.xxxx.com/xxxx',
// // 当进行代理时,Host 的源默认会保留(即Host是浏览器发过来的host),如果将changeOrigin设置为true,则host会变成target的值。
// changeOrigin: true,
// // 前缀 /api 是否被替换为特定目标,不过大多数后端给到的接口都是以/api打头,这个没有完全固定的答案,根据自己的业务需求进行调整
// rewrite: path => path.replace(/^\/api/, ''),
// }
// }
},
build: {
minify: "terser", // 必须开启:使用terserOptions才有效果
outDir: 'iot',
assetsDir: 'assets', // 指定生成静态文件目录
brotliSize: true, // 启用 brotli 压缩大小报告
chunkSizeWarningLimit: 2048, // chunk 大小警告的限制
terserOptions: {
compress: {
//生产环境时移除console
drop_console: true,
drop_debugger: true,
},
},
},
preview: {
port: 4001, // 指定开发服务器端口
strictPort: true, // 若端口已被占用则会直接退出
https: false, // 启用 TLS + HTTP/2
open: true, // 启动时自动在浏览器中打开应用程序
// proxy: { // 配置自定义代理规则
// '/api': {
// target: 'http://jsonplaceholder.typicode.com',
// changeOrigin: true,
// rewrite: (path) => path.replace(/^\/api/, '')
// }
// },
cors: true, // 配置 CORS
}
})
Add "serve": "vite" to the scripts of the package.json file, and it can be started with npm run serve when starting.
configure routing
vue-router
https://router.vuejs.org/
1. Install
npm install vue-router@4
2. Create a new router folder under the src folder. There is an index.js file under the folder for importing the methods required by the router and page path configuration, as well as parameter configuration and routing guards to determine whether there is a token or not to log in. If you are not logged in, jump to the login page. There is also a routes.js file specially used to configure the page path.
// 导入router所需的方法
import {
createRouter, createWebHashHistory } from 'vue-router'
// 导入路由页面的配置
import routes from './routes'
// 路由参数配置
const router = createRouter({
history: createWebHashHistory(),
routes,
})
router.beforeEach((to, from, next) => {
//一般路由守卫中会做一些鉴权和权限控制的事情
console.log(to)
if (to.meta && to.meta.title) {
document.title = to.meta.title
}
if(to.meta.isLogin){
let token = sessionStorage.getItem("token");
token ? next() : next('/login');
} else {
next();
}
})
export default router;
const routes = [
{
path: '/',
// name: '主页面',
meta: {
title: "主页面",
isLogin: true
},
redirect: "/home",
component: () => import("../views/Main.vue"),
children: [
/**
* 首页
* */
{
path: "/home",
meta: {
title: "首页",
icon: 'icon-zongjie',
isLogin: true
},
name: 'home',
component: () => import("../views/Home/Home.vue"),
},
{
path: "/work",
meta: {
title: "工作台",
icon: 'icon-zuchang',
isLogin: true
},
name: 'work',
children: [
{
path: "/work/work1",
meta: {
title: "工作台1",
icon: 'icon-zuchang',
isLogin: true
},
name: 'work1',
component: () => import("../views/Work/Work.vue"),
}
]
}
]
},
//登录页
{
path: "/login",
meta: {
title: "登录",
// icon: 'icon-zongjie',
isLogin: false
},
name: 'login',
component: () => import("../views/Login/Login.vue"),
},
/* url错误重定向到home */
{
path: "/:catchAll(.*)",
redirect: "/",
name: "notFound"
}
]
export default routes
3. In the App.vue public page, go directly to the routing page
<template>
<router-view></router-view>
</template>
<script setup>
</script>
<style scoped>
</style>
4. Build a routing page
and introduce less into the project
npm install less less-loader --save
Create a views folder under the src folder to write specific routing pages.
5. Introduce the ant-design component library
https://www.antdv.com/components/overview-cn/
npm install ant-design-vue --save
5. Configure the entry file, main.js under src, use these plug-ins and files.
import {
createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router/index'
import Antd from 'ant-design-vue';
import 'ant-design-vue/dist/antd.css';
const appst = createApp(App);
appst.use(router).use(Antd).mount('#app');
6. Write the menu and switch between routing pages
Write in Main.vue under the views folder under src
Select the layout:
<template>
<a-layout has-sider class="app-layout">
<a-layout-sider
@collapse="collapse"
v-model:collapsed="collapsed"
collapsible
:style="{ overflow: 'auto', height: '100%' }"
class="left-layout-slider"
>
<div class="logo"></div>
<a-menu v-model:selectedKeys="selectedKeys" @select="select" theme="dark" mode="inline" class="menu">
<template v-for="item in routes[0].children">
<a-sub-menu v-if="item?.children?.length > 0" >
<template #icon>
<span :class="`iconfont ${item.meta.icon}`"></span>
</template>
<template #title>
{
{
item.meta.title }}
</template>
<template v-for="i in item?.children" :key="i.path">
<a-menu-item>
<span :class="`iconfont ${i.meta.icon}`"></span>
<span class="nav-text">{
{
i.meta.title }}</span>
</a-menu-item>
</template>
</a-sub-menu>
<a-menu-item v-else :key="item.path">
<span :class="`iconfont ${item.meta.icon}`"></span>
<span class="nav-text">{
{
item.meta.title }}</span>
</a-menu-item>
</template>
</a-menu>
</a-layout-sider>
<a-layout :style="{height: '100%',width: collapsed ? 'calc(100% - 80px)' : 'calc(100% - 200px)',background:'#04070b' }">
<a-layout-header :style="{ background: '#16252e', padding: 0 }" class="app-layout-header">
<!-- <a-popconfirm placement="bottom">
<div class="app-layout-nameInfo">
<div>
<a-avatar :size="large">
<template #icon><UserOutlined /></template>
</a-avatar>
</div>
<div style="margin-left: 10px;">admin</div>
</div>
</a-popconfirm> -->
<!-- <a-popover>
<template #content>
<span class="iconfont icon-yanqi" style="color:#40a9ff"></span>
<a-button type="link" @click="banckClick">退出登录</a-button>
</template>
<div class="app-layout-nameInfo">
<div>
<a-avatar :size="large">
<template #icon><UserOutlined /></template>
</a-avatar>
</div>
<div style="margin-left: 10px;color: #ffffff;">admin</div>
</div>
</a-popover> -->
<a-dropdown>
<div class="app-layout-nameInfo">
<div>
<a-avatar size="large">
<template #icon><UserOutlined /></template>
</a-avatar>
</div>
<div style="margin-left: 10px;color: #ffffff;">admin</div>
</div>
<template #overlay>
<a-menu>
<a-menu-item>
<span class="iconfont icon-yanqi" style="color:#40a9ff"></span>
<a-button type="link" @click="banckClick">退出登录</a-button>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</a-layout-header>
<a-layout-content :style="{ margin: '24px 16px 0', overflow: 'initial' }">
<div :style="{ background: '#16252e', textAlign: 'center',height: '100%' }">
<router-view></router-view>
</div>
</a-layout-content>
<a-layout-footer :style="{ textAlign: 'center',background: '#04070b',color:'#fff' }">
v1.1.20230524172613
</a-layout-footer>
</a-layout>
</a-layout>
</template>
<script setup>
import {
defineComponent, ref, watch } from 'vue';
import routes from "@/router/routes";
import {
useRouter } from "vue-router";
import {
UserOutlined } from '@ant-design/icons-vue';
const router = useRouter()
const selectedKeys = ref(['4']);
const collapsed = ref(false);
const select = (e) => {
console.log(e)
router.push(e.key);
}
const banckClick = (e) => {
console.log("1222222222222")
router.replace("/login");
sessionStorage.removeItem("token")
}
const doResize = () => {
setTimeout(() => {
//手动触发窗口resize事件
if (document.createEvent) {
const event = document.createEvent("HTMLEvents");
event.initEvent("resize", true, true);
window.dispatchEvent(event);
}
}, 300);
};
const collapse = () => {
doResize();
}
watch(() =>router.currentRoute.value.path,(newValue,oldValue)=> {
selectedKeys.value = [newValue];
},{
immediate: true })
</script>
<style lang="less" scoped>
.left-layout-slider{
::-webkit-scrollbar {
display: none !important;
}
.menu{
height: calc(100% - 80px);
overflow-x: hidden;
overflow-y: scroll;
}
}
.app-layout{
width: 100%;
height: 100%;
overflow: hidden;
}
.logo {
height: 32px;
background: rgba(255, 255, 255, 0.2);
margin: 16px;
}
.site-layout .site-layout-background {
background: #fff;
}
[data-theme='dark'] .site-layout .site-layout-background {
background: #141414;
}
</style>
<style lang="less">
.ant-dropdown-menu-item, .ant-dropdown-menu-submenu-title{
padding: 0 6px!important;
}
.nav-text{
margin-left: 10px;
}
.ant-menu-inline.ant-menu-sub{
background: #001529!important;
}
.ant-menu-inline-collapsed{
.nav-text{
margin-left: 80px!important;
}
}
.app-layout-header{
position: relative;;
.app-layout-nameInfo{
position: absolute;
right: 15px;
top: 0;
display: flex;
}
}
</style>
7. Configure the overall style in style.css
:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
a {
font-weight: 500;
color: #646cff;
text-decoration: inherit;
}
a:hover {
color: #535bf2;
}
body {
margin: 0;
display: flex;
place-items: center;
min-width: 320px;
min-height: 100vh;
}
h1 {
font-size: 3.2em;
line-height: 1.1;
}
button {
border-radius: 8px;
border: 1px solid transparent;
padding: 0.6em 1.2em;
font-size: 1em;
font-weight: 500;
font-family: inherit;
background-color: #1a1a1a;
cursor: pointer;
transition: border-color 0.25s;
}
button:hover {
border-color: #646cff;
}
button:focus,
button:focus-visible {
outline: 4px auto -webkit-focus-ring-color;
}
.card {
padding: 2em;
}
#app {
margin: 0 auto;
/* text-align: center; */
width: 100vw;
height: 100vh;
overflow: hidden;
}
@media (prefers-color-scheme: light) {
:root {
color: #213547;
background-color: #ffffff;
}
a:hover {
color: #747bff;
}
button {
background-color: #f9f9f9;
}
}
/* //修改滚动条样式 */
::-webkit-scrollbar {
width: 8px;
height: 5px;
/* background: hsla(0, 0%, 100%, 0.6); */
}
::-webkit-scrollbar-track {
border-radius: 0;
}
::-webkit-scrollbar-thumb {
border-radius: 0;
background-color: rgba(95, 95, 95, 0.4);
transition: all 0.2s;
border-radius: 5px;
&:hover {
background-color: rgba(95, 95, 95, 0.7);
}
}
8. Introduce the Alibaba vector icon library
https://www.iconfont.cn/,
add the icon to the icon library project, and then download the package. After that, create a new iconfont folder under assets under the src folder of the project, and paste the contents of the downloaded package to the iconfont folder.
Then import it in the entry file and use it on the page
import "./assets/iconfont/iconfont.css";
At this point, the routing configuration is complete:
axios request
https://www.axios-http.cn/docs/intro
npm install axios
Create a new api folder under the src folder, create a baseApi.js file under the api folder to write the encapsulated request and
use the request data in the page, the get parameters are directly spelled to the back of the path to pass parameters, and the parameters of the post request are the above The second parameter, data. There are two parameters in the brackets when the post request is made, and the second parameter is the parameter to be passed. Configure the domain name in the proxy reverse code, and the first parameter of the request is the specific request interface address.
Obtain the token when logging in, and then save it in the local storage, and use the Token in the router guard to determine whether to log in. If you are logged in, you will be redirected to the home page, and if you are not logged in, you will be redirected to the login page.