vue3硅谷甄选02 | 封装svg组件 - axios二次封装

文章目录

  • 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,[email protected]下载指定版本

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接口统一管理

规范化接口管理,是项目接口请求逻辑更加清晰。

vue3硅谷甄选02 | 封装svg组件 - axios二次封装_第1张图片
api/user为例

问题:import type和import的区别

请求拦截器与响应拦截器的原理

你可能感兴趣的:(项目,vue.js,前端,javascript)