文章目录
- 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 formatsymbolId: '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 } = checkUserreturn { code: 200, data: { token } }},},// 获取用户信息{url: '/api/user/info',method: 'get',response: (request) => {//获取请求头携带tokenconst 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.statusswitch (status) {case 401:msg = 'token过期'breakcase 403:msg = '无权访问'breakcase 404:msg = '请求地址错误'breakcase 500:msg = '服务器出现问题'breakdefault:msg = '无网络'}ElMessage({type: 'error',message: msg,})return Promise.reject(error)//终止promise链},
)export default requestAxios
api接口统一管理
规范化接口管理,是项目接口请求逻辑更加清晰。
以api/user
为例