vue3 + vite 从 0 搭建【后台管理系统】

1. 使用Vite创建项目

npm create vite@latest
兼容性注意:
Vite v3+ 需要 Node.js 版本 14.18+,16+
Vite v2+ 需要 Node.js 版本 12.2.0+

使用Git Bash Here创建项目时,会出现无法上下切换选项的问题,所以一般是在当前文件夹下使用cmd创建项目

当前目录下打开cmd:

创建项目:

  1. Project name : <项目名称>
  2. Select a framework : <选择一个框架,一般都是vue吧>
  3. Select a variant : <不知道怎么翻译>,应该是语言基础吧?一般都是选择js或者ts

2. 启动项目并做基本的配置

  1. 使用 npm install 下载基本的依赖
  2. 使用 npm run dev 运行项目(这两步在创建完项目之后都会提示你做的)

vue3 + vite 从 0 搭建【后台管理系统】_第1张图片

这是一个基本的目录结构

  1. node_modules 存放(npm install之后)项目的依赖
  2. public 存放一些基本的公共文件,如 icon 等
  3. src 文件,开发最常用的文件夹,所有资源都放在这个文件夹下面

src 文件下几个文件的解读

  1. App.vue vue项目的主组件,createApp 时 需要传入的根组件,页面入口文件 ,所有页面都是在App.vue下进行切换的。是整个项目的关键,app.vue负责构建定义及页面组件归集。
    一般情况下,这个页面里面什么都不做,只放一个 router-view 路由视图组件就完事了
  2. main.js 项目的入口文件,主要作用是初始化vue实例,并引入所需要的插件
    • 实例化vue,上面提到的createApp
    • 引入各类插件,axios,elementUI 等,引入css样式
    • 存储用户的全局变量等
  3. package.json 这个文件要说的东西要多了 可以点击链接直接去看看这位师兄的,很详细
    另外 package.json 最好和 package-lock.json 一起学习使用
  4. vite.config.js vite的官方配置文档,东西多的很,不是一时半会就能学完的,只能说用到的时候去看就行

使用vite需要注意的几个点

  1. vite中没法使用@来指代src目录,需要手动配置
import path from "path";
resolve: {
  // 配置路径别名,解决不能使用@来指代src目录的问题
  alias: {
    "@": path.resolve(__dirname, "./src"),
  },
},
  1. vite中无法使用 require引入文件(CommonJS模块化规范),vite只支持ESModules模块化规范
    最好也别想着用什么插件强制使用require啥的,没必要

基本配置1:环境变量的配置

vitewebpack类似的环境变量配置方案,使用.env文件创建不同的环境配置文件,再在文件中进行相关的环境字段配置
注意,要想在全局中使用,首字母开头必须是 VITE
这样我们就可以在其他文件中使用 import.meta.env 访问到当前的环境变量了

vue3 + vite 从 0 搭建【后台管理系统】_第2张图片
vue3 + vite 从 0 搭建【后台管理系统】_第3张图片

package.json 还要进行配置,告诉项目,我们当前使用的是什么环境运行命令、打包命令
使用 --mode < env > 的形式

vue3 + vite 从 0 搭建【后台管理系统】_第4张图片

最后在 vite.config.js 也需要一点环境变量的配置
这里我这要配置了【静态资源 CDN】加速的配置,其他跟环境变量没有太大关系,主要是认识 loadEnv

import { defineConfig, loadEnv } from "vite";
import vue from "@vitejs/plugin-vue";
import path from "path";

export default defineConfig(({ command, mode }) => {
  // 静态文件路径
  /*
    loadEnv() 三个参数【https://cn.vitejs.dev/guide/api-javascript.html#loadenv】
    @mode:package.json中启动的时候,设置的 --mode  会读取到  中的变量
    @envDir:.env.xxx文件的路径
    @prefixes:默认情况下只有前缀为 VITE_ 会被加载,除非更改了 prefixes 配置
               现在将前缀更改为BASE_URL,这样我们就可以获取运维在部署时,就可以获取到CDN加载静态资源的前缀了,
               这个BASE_URL是跟运维约定好的字段,实际要根据自己的项目进行判断
  */
  // 如果没有找到 BASE_URL ,就使用 ./ 的目录
  const staticPath = loadEnv(mode, "./", "BASE_URL").BASE_URL || "./";
  return {
    // 静态资源cdn加速,如果是开发环境的话,就是用本地加载不使用cdn
    base: mode == "dev" ? "./" : staticPath,
    build: {
      assetsDir: "static", // 静态资源导出的文件名
    },
    plugins: [vue()],
    resolve: {
      // 配置路径别名,解决不能使用@来指代src目录的问题
      alias: {
        "@": path.resolve(__dirname, "./src"),
      },
    },
  };
});

基本配置2:封装axios,及请求的全局loading

  1. npm install axios 下载 axios
    下载之后不需要在main.js中进行引入,直接在需要的地方引入就行了

request.js文件
封装了【请求】、【响应】拦截器,三个常用的请求方法,全局loading 这样最基础的一个axios请求就封装好了

import axios from "axios";
import { getToken, removeToken } from "@/utils/auth";
// 引入全局loading的【开始loading】和【结束loading】
import { startLoading, endLoading } from "./requestLoading";
// 这里需要注意一点,我们的router不能使用 useRouter的形式,那个是vue文件中使用的,这里我们要自己引入
import myRouter from "../router/index";
import { ElMessage } from "element-plus";
// 引入环境变量
const myProcess = import.meta.env;
// 创建一个axios实例
const service = axios.create({
  baseURL: myProcess.VITE_APP_API,
  timeout: 1000 * 30, // 请求超时时间
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
});
// request请求拦截器
service.interceptors.request.use(
  (config) => {
    if (config.headers.showLoading) {
      // 开始请求的时候,调用startLoading
      startLoading();
    }
    if (getToken() && getToken() !== undefined) {
      config.headers["token"] = getToken(); // 让每个请求携带自定义请求头
    }
    return config;
  },
  // 咋说呢,这块其实要不要都无所谓
  (error) => {
    return Promise.reject(error);
  }
);
// response响应拦截器
service.interceptors.response.use(
  (response) => {
    endLoading();
    // 未登录或者登陆超时的时候,返回登录页面
    if ([401, 403].includes(response.data.code)) {
      removeToken();
      myRouter.push({ name: "login" });
    }
    return response;
  },
  (error) => {
    endLoading();
    ElMessage.error(error.message);
    return Promise.reject(error);
  }
);
/*
  @description:get方法,对应get请求
  @url:请求地址
  @params:请求参数
  @showLoading:是否在等待接口返回时,启动全局loading
*/
export const get = (url, params, showLoading) => {
  return service({
    url: url,
    method: "get",
    params,
    headers: { showLoading },
  });
};
/*
  @description:postFormData 适用于老接口,很多老接口使用的是formData进行传值
  @url:请求地址
  @params:请求参数
  @showLoading:是否在等待接口返回时,启动全局loading
*/
export function postFormData(url, data, showLoading) {
  return service({
    url,
    method: "post",
    headers: { "Content-Type": "application/x-www-form-urlencoded", showLoading },
    transformRequest: [
      function (data) {
        // 对 data 进行任意转换处理
        let ret = "";
        for (const it in data) {
          ret += encodeURIComponent(it) + "=" + encodeURIComponent(data[it]) + "&";
        }
        return ret;
      },
    ],
    data,
  });
}
// postJson
export function postJson(url, data, showLoading) {
  return service({
    url,
    method: "post",
    data,
    headers: { "Content-Type": "application/json", showLoading },
  });
}
// 这个导出可有可无,只能说导出去需要用到的时候再用吧
export default service;

requestLoading.js 文件

import { ElLoading } from "element-plus";
// 设置请求的数量
let requestNum = 0;
// 设置loading变量
let loading;
// 开始loading
export function startLoading() {
  if (requestNum === 0) {
    loading = ElLoading.service({
      lock: true,
      text: "Loading",
      background: "rgba(0, 0, 0, 0.7)",
    });
  }
  requestNum++;
}
// 结束loading
export function endLoading() {
  // 延迟 300ms 再调用 closeLoading 方法, 合并300ms内的请求
  // 当有请求中嵌套请求的情况也也可开启延时来解决
  setTimeout(closeLoading, 300);
  // closeLoading();
}
function closeLoading() {
  if (requestNum <= 0) return;
  requestNum--;
  if (requestNum === 0) {
    loading.close();
  }
}

基本配置3:vue-router路由的引入并使用

在创建vite项目的时候,vue-router并不是自带的,因为vue的本质是一个渐进式框架,我们需要手动引入并配置路由

npm install vue-router@4 点击查看vue-router官方文档

下载完成后,我们在src目录下新建一个router文件夹,文件夹中新建一个index.js,初始并实例化我们的router
index.js文件

// 引入创建路由的函数,和配置路由模式的函数
import { createRouter, createWebHashHistory } from "vue-router";

const routes = [
  {
    path: "/",
    name: "login",
    component: () => import(/* webpackChunkName: "登录页面" */ "../views/login/index.vue"),
  },
];

const router = createRouter({
  history: createWebHashHistory(),
  routes,
});

export default router;

最后引入到我们的main.js文件中,并使用

import { createApp } from "vue";
import "./style.css";
import App from "./App.vue";
// 引入路由文件
import router from "./router/index";

const app = createApp(App);
// 使用路由
app.use(router)
app.mount("#app");

基本配置4:配置css预处理器,这里以less为例

没有必要为它们安装特定的 Vite 插件,但必须安装相应的预处理器依赖
直接执行完命令就可以使用less
npm add -D less vite 官方文档CSS预处理器

基本配置5:layout页面的搭建

首先我们下载element-ui-plus,使用elementcontainer布局容器进行页面结构布局

npm install element-plus --save 官方文档

下载element icon 这个路由左侧的icon会用到
npm install @element-plus/icons-vue

mian.js中引入

import { createApp } from "vue";
import "./style.css";
import App from "./App.vue";
// 引入路由文件
import router from "./router/index";
// 引入ElementPlus
import ElementPlus from "element-plus";
import "element-plus/dist/index.css";
// 引入element icon
import * as ElementPlusIconsVue from "@element-plus/icons-vue";
const app = createApp(App);
// 引入element icon
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
  app.component(key, component);
}
// 使用路由
app.use(router);
// 使用ElementPlus
app.use(ElementPlus);
app.mount("#app");

挑选一个自己喜欢的布局容器
vue3 + vite 从 0 搭建【后台管理系统】_第5张图片
布局里面着重说一下侧边栏的设计

<template>
  <div class="common-layout">
    <el-container>
      <el-aside width="200px" class="aside_wrap">
        
        <el-scrollbar>
          <el-menu
            active-text-color="#ffd04b"
            background-color="#545c64"
            class="el-menu-vertical-demo"
            text-color="#fff"
            :default-active="defaultActive"
          >
            <myAside :mainRouterList="mainRouterList">myAside>
          el-menu>
        el-scrollbar>
      el-aside>
      <el-container>
        <el-header class="header_wrap">
          <myHeader>myHeader>
        el-header>
        <el-main class="main_wrap">
          <myMain>myMain>
        el-main>
        <el-footer>Footerel-footer>
      el-container>
    el-container>
  div>
template>
<script setup>
import myAside from "../layout/components/myAside/myAside.vue";
import myHeader from "../layout/components/myHeader/myHeader.vue";
import myMain from "../layout/components/myMain/myMain.vue";
import { useRoute, useRouter } from "vue-router";
import { ref } from "vue";
const myRouter = useRouter();
const myRoute = useRoute();
// 获取路由里的所有路由数组
const routerList = myRouter.options.routes;
// 获取layout里面的所有数组
const mainRouterList = routerList.find((v) => v.name == "home").children;
// 当前路由地址,用作左边侧边栏的高亮
const defaultActive = ref("");
defaultActive.value = myRoute.path;
script>
<style lang="less" scoped>
.aside_wrap {
  background-color: rgb(136, 136, 136);
  height: 100vh;
}
.header_wrap {
  background-color: rgb(220, 243, 255);
}
.main_wrap {
  background-color: #c7c7c7;
  height: 100%;
}
style>

使用递归的形式,循环调用el-menu里面的el-sub-menu和el-menu-item
myAside 文件里代码

<template>
  <template v-for="item in myMainRouterList" :key="item.name">
    <!-- 多个 -->
    <el-sub-menu :index="item.path" v-if="item?.children?.length > 0">
      <template #title>
        <el-icon><component :is="item?.meta?.icon"></component></el-icon>
        <span>Navigator One</span>
      </template>
      <!-- 递归调用自己 -->
      <myAside :mainRouterList="item?.children"></myAside>
    </el-sub-menu>
    <!-- 单个 -->
    <el-menu-item :index="item.path" v-else  @click="handleClickMenu(item)">
      <el-icon><component :is="item?.meta?.icon"></component></el-icon>
      <span>Navigator Two</span>
    </el-menu-item>
  </template>
</template>
<script setup>
import { defineProps } from "vue";
import { useRouter } from "vue-router";
const myRouter = useRouter()
// 获取父组件传递过来的参数
const myProps = defineProps(["mainRouterList"]);
const myMainRouterList = myProps.mainRouterList;
// 点击左侧侧边栏,进行路由跳转
const handleClickMenu = (subItem) => {
  myRouter.push(subItem?.path);
};
</script>

然后再随便撸一个路由

// 引入创建路由的函数,和配置路由模式的函数
import { createRouter, createWebHashHistory } from "vue-router";

const routes = [
  {
    path: "/",
    name: "login",
    component: () => import(/* webpackChunkName: "登录页面" */ "../views/login/index.vue"),
  },
  {
    path: "/home",
    name: "home",
    redirect: { name: "page1" },
    component: () => import("../views/layout/index.vue"),
    children: [
      {
        path: "/page1",
        name: "page1",
        meta: { icon: "CirclePlus", title: "页面11" },
        redirect: { name: "page1-1" },
        children: [
          {
            path: "/page1-1",
            name: "page1-1",
            meta: { icon: "Link", title: "页面1-1" },
            component: () => import("../views/pages/components/page1-1.vue"),
          },
          {
            path: "/page1-2",
            name: "page1-2",
            meta: { icon: "Position", title: "页面1-2" },
            component: () => import("../views/pages/components/page1-2.vue"),
          },
        ],
      },
      {
        path: "/page2",
        name: "page2",
        meta: { icon: "Female", title: "页面22" },
        component: () => import("../views/pages/page2.vue"),
      },
      {
        path: "/page3",
        name: "page3",
        meta: { icon: "Male", title: "页面33" },
        component: () => import("../views/pages/page3.vue"),
      },
    ],
  },
];

const router = createRouter({
  history: createWebHashHistory(),
  routes,
});

export default router;

vue3 + vite 从 0 搭建【后台管理系统】_第6张图片
好的,这样一个基本的后台管理系统框架就搭建完成了!

你可能感兴趣的:(vue3,vue3,vite,后台管理)