前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【vite+vue3+Ts+element-plus】肩并肩带你写后台管理之vite初始化项目以及项目准备工作

【vite+vue3+Ts+element-plus】肩并肩带你写后台管理之vite初始化项目以及项目准备工作

作者头像
十里青山
发布2023-04-28 15:58:17
6793
发布2023-04-28 15:58:17
举报
文章被收录于专栏:我的前端之路我的前端之路


github: https://github.com/heyongsheng/hevue3-admin 码云: https://gitee.com/ihope_top/hevue3-admin 线上体验地址 https://ihope_top.gitee.io/hevue3-admin

相信绝大多数的前端小伙伴就业初期或多或少都了解或使用过花裤衩大佬的vue-element-admin,部分小伙伴还看过框架配套的文章——手摸手撸后台系列。但很多小伙伴上来就用框架,很多实现方法都不了解怎么实现的,比如权限管理怎么做的?标签切换怎么做的?暗黑模式自定义主题又是如何实现的?诸如此类的细节还有很多,像我之前就不是很懂,用是会用,但是框架出点什么毛病就很难去修改。所以趁着失业,正好静下心来学习一下,用vite+vue3+element-plus+Ts来从0开始写一个通用的后台管理模板,ts由于我也不是太熟,写着用着,以不报错为主,所以ts用法部分仅供参考。

本篇文章会从初始化项目开始讲,尽量会提到每一个步骤,但由于写作经验不足,难免会有遗漏和啰嗦,欢迎指正,另外可能有些部分在写完之后又调整顺序,所以代码截图部分可能会出现后面的内容,不过不影响,成品我也会上传github。

另外因为在写文章期间代码也在不断调整,所以部分章节的截图可能和实际有出入,最终结果以实际代码为准,但整体思路基本没什么问题。

项目已开源,文章头部附有github及码云地址,也有体验链接,由于项目初期完善性不能保证,仅供参考,不建议作为公司项目使用,但我也会持续进行更新优化,欢迎大家提出自己的意见,也希望可以给个⭐️。

在此先列举一下文章主要涉及的知识点,文章不一定会按照以下顺序进行

  • vite项目初始化
  • element-plus的自动引入
  • 暗黑模式以及自定义主题的实现(主要使用scss+css变量)
  • 动态路由实现页面级权限、vue指令实现按钮级权限
  • 根据路由渲染侧边栏菜单
  • 标签栏的开发,以及keep-alive缓存
  • svg-sprite图标解决方案
  • 项目中所涉及的vue3知识
  • pinia的简单用法

除此之外还有一些其他方面的小坑,比如如何阻止浏览器默认填充密码时候的背景框、如何阻止浏览器填充密码还有各种官方文档没提到的报错等,文章里有些代码我没有说是因为我也不是太精通,但都是我四处查询资料查到的用法,如果你也是小白的话,照着抄就行了,基本不会出错。

因为着急找工作,所以文章和项目都有很多待优化的地方,如果我还能找到前端工作的话,会继续对文章和项目进行优化,也希望北京、上海的朋友如果有要求低(不要求学历)的工作的话可以推荐一下

使用vite初始化项目

首先我们使用vite来初始化项目,vite支持使用npm、yarn和pnpm来初始化项目,本文采用yarn的方式。

代码语言:javascript
复制
// 使用npm
npm create vite@latest
// 使用yarn
yarn create vite
// 使用pnpm
pnpm create vite

输入命令之后会提示我们输入项目名,如果我们已经建好项目,并且是在项目根目录执行的命令的话,只需输入一个点表示在当前目录创建就行,需要注意的是当前项目文件夹必须是空文件夹,否则vite会提示你是否清空已存在的文件继续

image.png
image.png

如果还没建项目,是在父目录执行的命令,则需输入要创建的项目名

image.png
image.png

之后会让我们选择使用的框架和选择使用js还是ts,我们选择vue和ts

image.png
image.png

之后我们按照提示命令进入项目目录执行命令安装依赖,运行项目即可

image.png
image.png
image.png
image.png

之后我们把一些默认的没用的文件给干掉,再在相关引用的地方把引用给清空

image.png
image.png

再把APP.vue里面的内容给清空,这个时候整个项目就是干干净净的了

image.png
image.png

vscode推荐插件

使用vscode的用户注意了,之前我们开发vue可能使用的是vetur插件,但是从vue3开始,官方已经推荐使用Volar了,所以我们需要把旧的插件给禁用或者直接卸载掉

image.png
image.png

再去扩展里搜索volar进行安装就可以了

image.png
image.png

建议进行此更换操作,否则可能引起意外的编辑器报错

vite配置目录别名

在项目开发中,我们通常会引用其他目录的文件,但如果文件不在一个目录的话,就会使用../的方式去查找,如果层级多的话很不方便,所以我们通常会给一些常用目录配置一个别名,比如下面我们就在vite中给src目录配置一个‘@’别名

首先我们需要安装node的类型声明文件,要不然ts可能会报警告

代码语言:javascript
复制
yarn add @types/node -D

之后我们在vite.config.ts中进行相关配置

代码语言:javascript
复制
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import path from 'path'                   // 增加此行代码

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    Components({
      resolvers: [ElementPlusResolver()],
    }),
  ],
  resolve: {                              // 增加此行代码
    alias: {                              // 增加此行代码
      '@': path.resolve(__dirname, 'src'),// 增加此行代码
    },                                    // 增加此行代码
  },                                      // 增加此行代码
})

之后还要在tsconfig.json中增加以下配置

代码语言:javascript
复制
    "paths": {
      "@/*": ["./src/*"]
    }
image.png
image.png

重置默认样式

我们都知道浏览器对于html标签都会有一些默认的样式,从而使页面美观,但不同的浏览器有不同的差异,所以我们一般都会在建项目时候重置浏览器样式,通常这个重置文件是各个项目通用的,大家如果没有也可以去网上搜一个。我们这里直接在assets/style文件夹下新建一个normalize.css,写入重置样式

代码语言:javascript
复制
html,
body,
div,
span,
applet,
object,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
hgroup,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 100%;
  font: inherit;
  font-weight: normal;
  vertical-align: baseline;
}

/* HTML5 display-role reset for older browsers */
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
  display: block;
}

ol,
ul,
li {
  list-style: none;
}

blockquote,
q {
  quotes: none;
}

blockquote:before,
blockquote:after,
q:before,
q:after {
  content: '';
  content: none;
}

table {
  border-collapse: collapse;
  border-spacing: 0;
}

th,
td {
  vertical-align: middle;
}

/* custom */
a {
  outline: none;
  color: #16418a;
  text-decoration: none;
  -webkit-backface-visibility: hidden;
}

a:focus {
  outline: none;
}

input:focus,
select:focus,
textarea:focus {
  outline: -webkit-focus-ring-color auto 0;
}

然后在main.ts中引入即可

代码语言:javascript
复制
// main.ts
import '@/assets/style/normalize.css'

vue-router

首先我们来安装一下vue-router

代码语言:javascript
复制
yarn add vue-router@4

之后在src目录下新建router/index.ts,写入一些基本路由,这里需要注意的是,vue3和vue2时候定义路由的方式发生了细微的变化,我还没有深入学习,暂时知道是这么写的就行。我们的路由通常分为无需权限路由(比如登录)和需要权限的路由(比如某个数据页面),我们这里先简单的定义一个主页面和登录页,meta里面的一些属性我们后面会讲

代码语言:javascript
复制
import { createRouter, createWebHashHistory, type RouteRecordRaw } from 'vue-router'

export const publicRouters: RouteRecordRaw[] = [
  {
    path: '/',
    component: () => import('@/layout/index.vue'),
    redirect: '/home',

    children: [
      {
        path: '/home',
        name: 'home',
        component: () => import('@/views/home/home.vue'),
        meta: { title: '首页', icon: 'shouye', affix: true, sort: '99.99' },
      },
    ],
    meta: {
      sort: '99',
    },
  },
  {
    path: '/login',
    name: 'login',
    component: () => import('@/views/login/login.vue'),
    meta: {
      hidden: '1',
    },
  },
]
const router = createRouter({
  history: createWebHashHistory(),
  routes: publicRouters,
})

export default router

这里需要注意的是,vue-router指定路由模式从字符串变为了使用方法,historycreateWebHistory(地址栏不带#),hashcreateWebHashHistory(地址栏带#)

这时候我们可能还会发现,编辑器中ts会报找不到vue文件相关类型声明的错误

image.png
image.png

解决办法:我们可以在根目录创建一个env.d.ts,在里面写入以下内容

代码语言:javascript
复制
/// <reference types="vite/client" />

declare module '*.vue' {
  //引入vue模块中ts的方法
  import type { DefineComponent } from 'vue'
  // 定义vue組件以及类型注解
  const component: DefineComponent<{}, {}, any>
  export default component
}

之后还要记得在tsconfig.ts中引入

image.png
image.png

现在报错没有了,我们还需要在main.ts中进行引入

代码语言:javascript
复制
import router from './router'

createApp(App).use(router).mount('#app')
image.png
image.png

pinia和axios

在vue2中,我们往往使用vuex来做全局的状态管理,在vue3中,官方推荐我们使用pinia来做全局的状态管理,由于官方文档十分详细易懂,我使用的时候也没发现什么坑,这里就不啰嗦了,直接讲流程,有使用经验的建议跳过。

安装pinia和axios

代码语言:javascript
复制
yarn add axios
yarn add pinia

pinia安装之后需要先在main/ts引入。

代码语言:javascript
复制
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { createPinia } from 'pinia'
import '@/assets/style/normalize.css'

createApp(App).use(router).use(createPinia()).mount('#app')
image.png
image.png

一般后台管理系统会有用户管理和后台使用人员,为了区分,这里我们把后台使用人员称之为员工,pinia使用时需要根据存储用途创建对应的实例,这里我们先创建一个员工相关的pinia实例。

代码语言:javascript
复制
import { defineStore } from 'pinia'
export const useStaffStore = defineStore('staff', {
  state: () => ({
    token: '',
    staff: null,
  }),
  actions: {
    setToken(token: string) {
      this.token = token
    },
    logOut() {
      this.token = ''
    },
  },
})

这里简单说明一下,pinia用defineStore创建实例,接收的第一个参数要求是一个独一无二的名字,第二个配置项就是常用的配置了,在pinia中,你可以认为 state 是 store 的数据 (data),getters 是 store 的计算属性 (computed),而 actions 则是方法 (methods),相比vuex,pinia没有mutations

之后我们创建一个操作token的常用方法utils/auth.ts

代码语言:javascript
复制
const TokenKey = 'token'

export function getToken() {
  return localStorage.getItem(TokenKey)
}

export function setToken(token: string) {
  return localStorage.setItem(TokenKey, token)
}

export function removeToken() {
  return localStorage.setItem(TokenKey, '')
}

我们先在根目录创建一下环境变量,我这里参数仅供参考啊,实际以你实际项目为主

代码语言:javascript
复制
// .env.development
MODE = 'development'
VITE_APP_BASE_PREFIX = '/api'
VITE_APP_BASE_API = http://localhost:6001

// .env.production
MODE = 'production'
VITE_APP_BASE_PREFIX = '/accountApi'

之后我们来对axios进行封装,首先封装一个utils/request.ts,做一些简单的拦截和返回结果处理的封装

代码语言:javascript
复制
import axios from 'axios'
import { useStaffStore } from '@/stores/staff'
import { getToken } from '@/utils/auth'
import { ElNotification } from 'element-plus'

// create an axios instance
const service = axios.create({
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
  },
  timeout: 20000, // request timeout
})

service.interceptors.request.use(
  (config) => {
    const staffStore = useStaffStore()
    config.baseURL = import.meta.env['VITE_APP_BASE_PREFIX']

    if (staffStore.token) {
      config.headers['x-authorization'] = 'Bearer ' + getToken()
    }
    return config
  },
  (error) => {
    console.log(error) // for debug
    return Promise.reject(error)
  }
)

service.interceptors.response.use(
  (response) => {
    const staffStore = useStaffStore()
    const res = response.data
    if (res.code === 401) {
      ElNotification.error({
        title: '错误',
        message: res.msg,
      })

      staffStore.logOut()
      return Promise.reject(res)
    } else if (res.code !== 200) {
      ElNotification.error({
        title: '错误',
        message: res.msg || '网络错误,请稍后重试',
      })
      return Promise.reject(res)
    } else {
      return res
    }
  },
  (error) => {
    console.log(error) // for debug
    const errContent = error.response
    const staffStore = useStaffStore()
    if (errContent?.status === 401) {
      ElNotification.error({
        title: '错误',
        message: errContent.data.msg,
      })

      staffStore.logOut()
      return Promise.reject(error)
    } else {
      ElNotification.error({
        title: '错误',
        message: errContent?.data?.msg || '网络错误,请稍后重试',
      })
      return Promise.reject(error)
    }
  }
)

export default service

之后我们来vite.config.ts中配置一下跨域,这里我们还需要对之前的写法做一些改造

image.png
image.png

之后再加入跨域配置

代码语言:javascript
复制
server: {
  proxy: {
    [config.VITE_APP_BASE_PREFIX]: {
      target: config.VITE_APP_BASE_API,
      changeOrigin: true,
      rewrite: (path) =>
        path.replace(new RegExp(`^${config.VITE_APP_BASE_PREFIX}`), ''),
    },
  },
},
image.png
image.png

这里写的比较简略,如果有任何建议或者问题,欢迎提出,我会完善

现在我们的项目初始化就完成啦,下一章我们来学习如何自动引入element-plus、element-plus图标,以及自定义图标的解决方案。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-04-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 使用vite初始化项目
  • vscode推荐插件
  • vite配置目录别名
  • 重置默认样式
  • vue-router
  • pinia和axios
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档