文章目录
- vue3硅谷甄选02
- 功能1:封装svg组件
- SVG图标配置
- svg封装成组件
- svg组件注册为全局组件
- 自定义统一注册全局组件的插件
- 自定义插件的原理
- 插件的使用 app.use(plugin, [options])
- 功能2:axios二次封装
- 使用mock插件构造数据
- axios二次封装
- api接口统一管理
- 问题:import type和import的区别
- 请求拦截器与响应拦截器的原理
vue3硅谷甄选02
还在更新中 最后更新时间9.26
功能1:封装svg组件
SVG图标配置
在开发项目的时候经常会用到svg矢量图,对页面性能有很大的提升。而且SVG文件比img要小的很多,放在项目中几乎不占用资源。
安装SVG管理插件
- 预加载 在项目运行时就生成所有图标,只需操作一次 dom
- 高性能 内置缓存,仅当文件被修改时才会重新生成
pnpm install vite-plugin-svg-icons -D
在vite.config.ts
中配置插件
//引入svg需要用到插件
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import path from 'path'
export default () => {
return {
plugins: [
// .....
createSvgIconsPlugin({
// svg图标的存储位置
iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],
// Specify symbolId format
symbolId: 'icon-[dir]-[name]',
}),
],
}
}
入口文件导入
import 'virtual:svg-icons-register'
测试:在vue文件中使用svg
// svg 标签相当于容器 use表示使用svg图标,xlink:href的属性值标识执行哪一个图标 #icon-xxx 这里的xxx是svg的图标名。fill属性表示填充的颜色。
// 这里不用引入,会去配置的src/assets/icons下找文件。
<svg> //svg的width和height属性可以调节图标的大小
<use xlink:href="#icon-phone" fill='red'></use>
</svg>
svg 和 use标签 属于 SVG Sprite 技术,介绍项目的时候可以说使用了SVG Sprite 技术(可以搜索了解下)。
svg封装成组件
很多模块都需要使用图标,为了方便使用,将svg封装为组件。
//src/components/SvgIcon/index.vue
<template>
<svg :style="{width,height}">
<use :xlink:href = "prefix+name" :fill="color"></use>
</svg>
</template>
<script setup lang="ts">
interface iconConfig {
prefix?: string, //:xlink:href属性值的前缀
name: string,
color?: string,
width?: string,
height?: string,
}
//接受父组件传递过来的参数
withDefaults(defineProps<iconConfig>(), {
prefix:'#icon-',
color:'' ,
width:'16px',
height:'16px',
})
</script>
svg组件注册为全局组件
全局组件注册语法:vue.conponent('组件名',组件值)
项目的文件结构很复杂,引入时路径寻找很麻烦。将svg组件注册为全局组件,就不用每次使用时都引入。
// main.ts
import SvgIcon from '@/components/SvgIcon/index.vue'
app.component('SvgIcon', SvgIcon) //第一个参数为组件名,第二个参数为对应组件
注册完成后可以在任意组件中不引入就使用
<svg-icon name="xxx" color="xxx" width="xxx" height="xxx"></svg-icon>
存在问题:如果有100个全局组件就需要注册100次全局组件
解决办法:自定义插件实现统一注册全局组件的功能
自定义统一注册全局组件的插件
插件的作用:注册整个项目的全局组件
插件的使用
//main.ts
import gloalComponent from '@/components'
//安装自定义插件
app.use(gloalComponent);
app.use(插件)
实际上就是调用插件的install()
,还会把app
应用实例传参给install
方法
插件的定义
实现原理:install
方法的参数是app
应用实例,可以利用app
应用实例的component
方法注册全局组件。
//components/index.ts
import SvgIcon from './SvgIcon/index.vue'
// 有新的全局组件可以引入后,添加进allGloablComponent 对象
const allGloablComponent = { SvgIcon }
// 对外暴露插件对象
export default {
//接受app应用实例参数
install(app) {
Object.keys(allGloablComponent).forEach((key) => {
app.component(key, allGloablComponent[key])
})
},
}
引出知识点:如何自定义插件?自定义插件的原理是什么?
自定义插件的原理
插件文件的类型
- 包含
install
方法的对象 - 函数,这个函数被当作
install
方法。
install(app, options)
- app:app应用实例
- options:传入的选项
插件的使用 app.use(plugin, [options])
- 语法:
app.use(plugin, [options])
- 作用:
app.use(plugin)
执行时相当于执行插件的install()
,将app
应用实例传递给install()
的第一个参数 - 返回值:返回一个应用实例,可以链式添加新的插件
- 参数
- plugin 使用的插件名
- options 执行插件时将
options
参数传递给install
方法的第二个参数
use方法的原理
- 利用
Set
结构存储插件,当存在该插件时抛出异常;app.use
会自动阻止多次注册相同插件。 - 通过判断是否存在
install
方法或是否是函数,执行对应的插件。 - 执行插件时将
app
上下文实例和options
作为参数传入。 - 返回
app
实例,实现链式调用
function createApp(rootComponent, rootProps = null) {
// ……
const installedPlugins = new Set();
const app = (context.app = {
// ……
use(plugin, ...options) {
if (installedPlugins.has(plugin)) {
warn(`Plugin has already been applied to target app.`);
}
else if (plugin && shared.isFunction(plugin.install)) {
installedPlugins.add(plugin);
plugin.install(app, ...options);
}
else if (shared.isFunction(plugin)) {
installedPlugins.add(plugin);
plugin(app, ...options);
}
else {
warn(`A plugin must either be a function or an object with an "install" ` +
`function.`);
}
return app;
},
// ……
});
return app;
};
功能2:axios二次封装
使用mock插件构造数据
作用:mockjs
生成随机数据。当前端使用mock
模拟的数据接口时,mockjs
进行数据返回,并拦截ajax
请求不发送给后台。
1.安装依赖
pnpm install -D vite-plugin-mock mock.js
这里vite-plugin-mock的版本为2.9.6,vite-plugin-mock@2.9.6下载指定版本
2.在 vite.config.js 配置文件启用插件
import { UserConfigExport, ConfigEnv } from 'vite'
import { viteMockServe } from 'vite-plugin-mock'
import vue from '@vitejs/plugin-vue'
export default ({ command })=> {
return {
plugins: [
vue(),
viteMockServe({
mockPath: './src/mock',//!!!!!!
localEnabled: command === 'serve',
}),
],
}
}
老师视频把mockPath删除了,我删除之后会报错404,这里不能删除!
在根目录创建mock文件夹,mock
文件夹里面存放假数据。
在mock文件夹下创建user.ts
//用户信息数据
//createUserList函数执行返回一个数组,数组里的每一个元素是一个用户
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',
},
]
}
//对外暴露一个数组,数组中包含两个接口
// 接口1:用户登录接口
// 接口2:获取用户信息接口
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
测试接口是否可用(前提是已经安装了axios
)
axios({
url: '/api/user /login',
method:"post",
data:{
username:'admin',
password:'111111',
}
})
axios二次封装
目的:使用axios的请求拦截器与响应拦截器
- 请求拦截器:可以在请求拦截器中处理一些业务(开始进度条、请求头携带公共参数)
- 响应拦截器:使用响应拦截器,可以在响应拦截器中处理一些业务(进度条结束、简化服务器返回的数据、处理http网络错误)
1.安装axios
pnpm i axios
2.二次封装axios,创建utils/request.js
文件,其中utils
文件夹存放常用功能性文件。
//引入axios
import axios from 'axios'
import { ElMessage } from 'element-plus'
/*
1.利用axios对象的方法create,去创建一个axios实例
2.参数是配置对象
*/
const requestAxios = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API, //基础路径携带api,发送请求的时候不用写前面的api了,自动添加在前面
timeout: 5000, //请求超时的时间5s
})
//请求拦截器
requestAxios.interceptors.request.use((config) => {
//config:配置对象,headers请求头携带公共参数
return config
})
//响应拦截器
//参数1成功的回调,参数2失败的回调
requestAxios.interceptors.response.use(
(res) => {
return res.data
},
(error) => {
//案例:处理网络错误
let msg = ''
let status = error.response.status
switch (status) {
case 401:
msg = 'token过期'
break
case 403:
msg = '无权访问'
break
case 404:
msg = '请求地址错误'
break
case 500:
msg = '服务器出现问题'
break
default:
msg = '无网络'
}
ElMessage({
type: 'error',
message: msg,
})
return Promise.reject(error)//终止promise链
},
)
export default requestAxios
api接口统一管理
规范化接口管理,是项目接口请求逻辑更加清晰。
以api/user
为例