笔记地址:https://24kcs.github.io/vue3_study/chapter1/01_%E5%88%9D%E8%AF%86TS.html
一、创建项目
1、项目初始化
执行npm create vite@latest
命令,根据提示,给项目命名,选择vue3框架、ts 语言
2、下载依赖
npm install
3、运行
npm run dev
二、前置工作
1、eslint 校验代码工具配置
2、prettier 格式化工具配置
3、husky 配置
4、commitLint 配置
5、项目中集成 elment-plus
main.ts 中
import ElementPlus from "element-plus"
//@ts-ignore
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
import 'element-plus/dist/index.css'
let app = createApp(App)
app.use(ElementPlus, {
locale: zhCn
})
app.mount('#app')
5、src 文件夹别名配置
vite.config.ts
resolve: {
alias: {
"@": path.resolve("./src") //相对路径别名配置,使用 @ 代替 src
}
}
tsconfig.json
"compilerOptions": {
"baseUrl": "./", //解析非相对模块的基地址,默认为当前目录
"paths": {
"@/*": ["src/*"]
}
},
6、配置项目环境变量
- 根目录创建 .env.development 和 .env.production
.env.development
# 变量必须以 VITE_ 为前缀才能暴露给外部使用
NODE_ENV = "development"
VITE_APP_TITLE = "硅谷甄选运营平台-开发环境"
VITE_APP_BASE_API = "/dev-api"
VITE_SERVE = "http://xxx.com"
.env.production
# 变量必须以 VITE_ 为前缀才能暴露给外部使用
NODE_ENV = "production"
VITE_APP_TITLE = "硅谷甄选运营平台-生产环境"
VITE_APP_BASE_API = "/prod-api"
VITE_SERVE = "http://yyy.com"
- 使用
console.log(import.meta.env)
7、svg 图标的封装与使用
- 1:下载 vite-plugin-svg-icons
npm i vite-plugin-svg-icons -D
- 2:vite.config.ts中配置,
//引入path
import path from 'path'
// 引入 createSvgIconsPlugin
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
export default defineConfig({
plugins: [
vue(),
createSvgIconsPlugin({
iconDirs: [path.resolve(process.cwd(), "src/assets/icons")], //svg 图标需要放到 src/assets/icons 目录下
symbolId: "icon-[dir]-[name]"
})
],
})
- 3:在入口文件 main.ts 中导入配置项
//导入配置项
import "virtual:svg-icons-register"
- 4:使用
以 iconfont 字体图标库为例- 图标库中找到对应图标(star),点击下载,在弹框中复制 SVG 代码
- 在 src/assets/icons 目录下,新建 star.svg 文件,将 上面复制的 SVG 代码复制进去(此时浏览器打开文件可以显示图标)
- 组件内使用,
<svg>
<!-- href 也可以使用 xlink:href,值需要固定为 #icon-svg图标名,fill 为颜色-->
<use href="#icon-star" fill="yellow"></use>
</svg>
8、注册自定义的全局组件
注册全局组件有两种方法:
- 方法1:每增加一个全局组件,就手动引入,然后进行注册
//main.ts 文件中
//引入全局组件
import SvgIcon from '@/components/SvgIcon/index.vue'
//注册全局组件
app.component("SvgIcon",SvgIcon)
注:如果要注册很多全局组件,这里就需要引入、注册多次,比较麻烦
- 方法2:components 下新增 index.ts,在里面引入组件,遍历注册组件
// index.ts
//引入 全局组件
import SvgIcon from "./SvgIcon/index.vue"
import Test from "./test.vue"
let allGloabComponent ={
SvgIcon,
Test
}
//对外暴露插件对象
export default {
//install 方法会在页面初始化时候执行,该方法有一个参数,该参数是 main.ts 中创建的 app 对象
install(app) {
// console.log("allGloabComponent")
// 循环注册全局组件
Object.keys(allGloabComponent).forEach(key => {
app.component(key, allGloabComponent[key])
})
}
}
//main.ts 文件
//引入自定义插件对象,注册整个项目全局组件
import gloablComponent from "@/components"
console.log(gloablComponent)
//安装自定义插件(gloablComponent是带有 install 方法的一个对象,安装gloablComponent以后,初始化时,会执行install方法)
app.use(gloablComponent)
9、集成sass,并重置样式
- 下载 sass
- 创建 src/style/index.scss、src/style/reset.scss、src/style/variable.scss
- index.scss 是全局样式文件,要在 main.ts 中引入
import "./style/index.scss"
。index.scss 里面会引入其他所有 scss 文件,这个文件中,没有办法使用 $ 变量,所以需要另外创建 scss 文件(variable.scss ,名称随意,但是要跟 vite.config.js 中统一),专门用来存放变量 - reset.scss 是统一全局样式的文件,可以在 npm 官网搜索 reset.scss 文件,把内容复制过来
- variable.scss 是存放 scss 变量的文件(需要在 vite.config.ts 中配置)
- index.scss 是全局样式文件,要在 main.ts 中引入
1)index.scss
// 引入全局样式
@import "./reset.scss"; //后面必须加分号,否则会报错
2)variable.scss
$base-color: green;
$title-color: blue;
3)vite.config.ts
export default defineConfig({
css: {
preprocessorOptions: {
scss: {
javascriptEnabled: true,
additionalData: '@import "./src/style/variable.scss";' //引入存放scss全局变量的文件
}
}
}
})
@import "./src/style/variable.scss";
后一定要加分号,否则会报错。
10、mock 接口
安装依赖:https://github.com/vbenjs/vite-plugin-mock
- 下载 vite-plugin-mock
npm install -D vite-plugin-mock@2.9.6 mockjs
- 在 vite.config.js 中配置文件启用插件(注意:这里 vite-plugin-mock 要用 2.9.6 版本,否则在配置
localEnabled: command === "serve"
时会报错,不清楚什么原因 )
// 引入 mock 方法
import { viteMockServe } from 'vite-plugin-mock'
export default defineConfig(( { command } ) => {
return {
plugins: [
vue(),
viteMockServe({
localEnabled: command === "serve"
})
}
})
- 在根目录创建mock文件夹:去创建我们需要mock数据与接口!!!
- 在mock文件夹内部创建一个user.ts文件
//用户信息数据
function createUserList() {
return [
{
userId: 1,
avatar:
'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
username: 'admin',
password: '111111',
desc: '平台管理员',
roles: ['平台管理员'],
buttons: ['cuser.detail'],
routes: ['home'],
token: 'Admin Token',
},
{
userId: 2,
avatar:
'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif',
username: 'system',
password: '111111',
desc: '系统管理员',
roles: ['系统管理员'],
buttons: ['cuser.detail', 'cuser.user'],
routes: ['home'],
token: 'System Token',
},
]
}
export default [
// 用户登录接口
{
url: '/api/user/login',//请求地址
method: 'post',//请求方式
response: ({ body }) => {
//获取请求体携带过来的用户名与密码
const { username, password } = body;
//调用获取用户信息函数,用于判断是否有此用户
const checkUser = createUserList().find(
(item) => item.username === username && item.password === password,
)
//没有用户返回失败信息
if (!checkUser) {
return { code: 201, data: { message: '账号或者密码不正确' } }
}
//如果有返回成功信息
const { token } = checkUser
return { code: 200, data: { token } }
},
},
// 获取用户信息
{
url: '/api/user/info',
method: 'get',
response: (request) => {
//获取请求头携带token
const token = request.headers.token;
//查看用户信息是否包含有次token用户
const checkUser = createUserList().find((item) => item.token === token)
//没有返回失败的信息
if (!checkUser) {
return { code: 201, data: { message: '获取用户信息失败' } }
}
//如果有返回成功信息
return { code: 200, data: { checkUser } }
},
},
]
- 安装axios
npm install axios
- 在main.ts中测试接口,接口返回 200 表示请求成功
//测试接口
import axios from "axios"
axios({
url: "/api/user/login",
method: "post",
data: {
username: 'admin',
password: '111111',
}
})
11、axios 二次封装
目的:
1、使用请求拦截器,可以在请求拦截器中处理一些业务(开始进度条、请求头携带公共参数等)
2、使用响应拦截器,可以在响应拦截器中处理一些业务(结束进度条,简化服务器返回的数据,处理 http 网络错误)
在创建src/utils/request.ts
// 进行 axios 二次封装:使用请求与响应lan jie q
//引入 axios
import axios from "axios";
// 引入 element-plus 的提示框组件,在请求失败的时候,弹出失败信息
import { ElMessage } from "element-plus";
// 这里通过 axios 创建的 request 实例,可以增加一些配置信息
//第一步:利用 axios 对象的create方法,创建一个axios实例(其中可配置:基础路径、超时时间)
let request = axios.create({
// 这里的 import.meta.env.VITE_APP_BASE_API 读取到的是 .env.xxx(如.env.development) 文件中的相关配置
baseURL: import.meta.env.VITE_APP_BASE_API,
// 配置超时时间
timeout: 5000
});
// 第一步:请求拦截器
request.interceptors.request.use((config) => {
// config 里面包含了 baseURL、method、url、headers、timeout 等
// console.log(config)
// 这里要 return 出去,否则请求发不出去
return config;
})
// 第二步:响应拦截器
request.interceptors.response.use((response:any) => {
//成功的回调,作用:简化数据
// response 中包含 请求的config(数据同第17行)、接口响应的 data、状态 status、headers等
// console.log(response)
// 将接口响应的数据返回
return response.data;
}, (error) => {
// 错误回调,处理错误信息
// error 是接口请求失败的信息,包含 code 和 config、message、response(接口失败的信息)
// console.log(error)
let status = error.response.status, message = "";
switch (status) {
case 401:
message = "TOKEN过期";
break;
case 403:
message = "无权访问";
break;
case 404:
message = "请求地址错误";
break;
case 500:
message = "服务器出现问题";
break;
default:
message = "网络出现问题";
break;
}
ElMessage({
type: "error",
message
})
return Promise.reject(error);
})
export default request;
组件内使用:
import { onMounted } from "vue";
import request from "@/utils/request.ts"
onMounted(() => {
request({
url: "/user/login",
method: "post",
data: {
username: 'admin',
password: '111111'
}
}).then((res) => {
console.log(res)
})
})
12、API 接口统一管理
创建apis目录,按照模块创建目录,配置接口地址及出入参数据类型,如:
src/apis/user/index.ts:该文件配置接口接口、接口出入参的类型
src/apis/user/type.ts:定义出入参的数据类型
//src/apis/user/index.ts
// 统一管理项目用户相关的接口
import request from "@/utils/request";
// import 语法会将整个模块文件加载进去
// import type 只会从模块中获取类型信息
import type { loginForm, loginResponseData, userResponseData } from "./type";
enum API {
LOGIN_URL = "/user/login",
USERINFO_URL = "/user/info"
}
export const reqLogin = (data:loginForm) => request.post<any,loginResponseData>(API.LOGIN_URL, data)
export const reqUserInfo = () => request.post<any,userResponseData>(API.USERINFO_URL)
//type.ts
// 定义登录接口需要携带的参数的 ts 类型
export interface loginForm {
username: string,
password: string
}
interface dataType {
token: string
}
// 定义登录接口返回的数据类型
export interface loginResponseData {
code: number,
data: dataType
}
interface checkUser {
userId: number,
avatar: string,
username: string,
password: string,
desc: string,
roles: string[],
buttons: string[],
routes: string[],
token: string
}
interface user {
checkUser: checkUser
}
// 定义接口返回用户信息相关的数据类型
export interface userResponseData {
code: number,
data: user
}
组件中发送请求:
import { onMounted } from "vue";
import { reqLogin } from "./apis/user/index.ts"
onMounted(() => {
reqLogin({username: "admin", password: "111111"}).then((res) => {
console.log(res)
})
})
13、路由配置
- 创建 src/router/index.ts(路由相关配置)、src/router/routes.ts(路由列表)
- 创建 src/views 目录,里面按模块创建目录及对应页面组件如:src/views/404/index.vue、src/views/home/index.vue、src/views/login/index.vue
- 入口文件 src/main.ts 引入路由并进行注册
- 入口模版组件使用
<router-view></router-view>
显示路由组件
//src/router/index.ts
// 引入创建路由实例的方法,和创建 hash(createWebHashHistory) / history(createWebHistory) 模式的方法
import { createRouter, createWebHashHistory } from "vue-router"
import { constantRoute } from "./routes.ts"
let router = createRouter({
// 配置路由模式:hash
history: createWebHashHistory(),
// 配置路由
routes: constantRoute,
//路由切换时,页面滚动到顶部左侧
scrollBehavior() {
return {
top: 0,
left: 0
}
}
});
export default router;
//src/router/routes.ts
//对外暴露配置的路由
export const constantRoute = [
{
path: "/login",
name: "登录",
component: () => import ("@/views/login/index.vue")
},
{
path: "/404",
name: "404",
component: () => import ("@/views/404/index.vue")
},
{
path: "/",
name: "home",
component: () => import ("@/views/home/index.vue")
},
{
// 路由都匹配不上时,匹配这个任意路由,重定向到 404
path: "/:pathMatch(.*)",
name: "any",
redirect: "/404"
}
]
// main.ts
// 引入路由
import router from "./router"
//注册路由
app.use(router)
<!--App.vue-->
<template>
<router-view></router-view>
</template>