You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

258 lines
13 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 17 | 实战痛点3Vue 3 中如何集成第三方框架
你好,我是大圣。
在上一讲中我给你介绍了如何在Vue 3中实现页面和接口的权限管理。我们把vue-router的动态路由、导航守卫、axios的接口拦截等功能配合到一起使用实现了页面的权限控制这也算是Vue中进阶使用vue-router和axios的一个方式。
今天我们再来学习另一个进阶玩法聊一下如何在Vue 3中使用和引入更多的框架。可别小看这里的门道有的第三方工具框架跟Vue耦合性不高而有的需要做适配这一讲我就详细给你说说实操中的注意事项帮助你在提高开发效率的同时少走弯路。
## 独立的第三方库
首先我们要介绍的第三方框架是axios这是一个完全独立于Vue的框架我们可以使用axios发送和获取网络接口数据。在Vue、React框架下axios可以用来获取后端数据。甚至在Node.js环境下也可以用axios去作为网络接口工具去实现爬虫。
axios这种相对独立的工具对于我们项目来说引入的难度非常低。通常来说使用这种独立的框架需要以下两步。
以页面进度条工具NProgress为例第一步是我们先进入到项目根目录下使用下面的命令去安装NProgress。
```bash
npm install nprogress -D
```
第二步就是在需要使用NProgress的地方进行import的相关操作比如在页面跳转的时候我们就需要使用NProgress作为进度条。导入NProgress库之后我们就不需要使用Vue3的插件机制进行注册只需要通过router.beforeEach来显示进度条通过afterEach来结束进度条就可以了。
```javascript
import NProgress from 'nprogress' // progress bar
router.beforeEach(async (to, from, next) => {
// start progress bar
NProgress.start()
})
router.afterEach(() => {
// finish progress bar
NProgress.done()
})
```
在项目中我们之后还会依赖很多和NProgress类似的库比如处理Excel的xlsx库处理剪切板的clipboard库等等。
## 组件的封装
下面我们以可视化组件为例,来分析复杂组件的封装。之所以选择可视化组件为示例,是因为管理系统中的统计数据、销售额数据等等,都喜欢用饼图或柱状图的方式来展示。
虽然可视化本身和Vue没有太大关系但我们需要在页面中以组件的形式显示可视化图表。对此我们的选择是用可视化框架ECharts去封装Vue的组件来实现可视化组件。
我们再简单介绍一下可视化框架的使用方式不管你选择用百度的ECharts还是蚂蚁的G2等框架在框架的使用方法上都是类似的。首先你需要完成图表库的配置并且填入图表数据然后把这个数据渲染在一个DOM上就可以了。
下面的代码展示了一个ECharts的入门案例代码中我们首先使用echarts.init初始化一个DOM标签然后在options中配置了图表的结构包括标题、x轴等并且我们还通过series配置了页面的销量数据最后使用myChart.setOption的方式渲染图表就可以了。
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>ECharts</title>
<!-- 引入刚刚下载的 ECharts 文件 -->
<script src="echarts.js"></script>
</head>
<body>
<!-- 为 ECharts 准备一个定义了宽高的 DOM -->
<div id="main" style="width: 600px;height:400px;"></div>
<script type="text/javascript">
// 基于准备好的dom初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
// 指定图表的配置项和数据
var option = {
title: {
text: 'ECharts 入门示例'
},
tooltip: {},
legend: {
data: ['销量']
},
xAxis: {
data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
},
yAxis: {},
series: [
{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}
]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
</script>
</body>
</html>
```
看上面的代码我们先配置好图表需要的数据然后使用setOption初始化图表之后在浏览器中打开项目主页面就可以看到下图所示的这种可视化结果。在你理解了ECharts的使用方法后下一个要解决的问题是我们该如何在Vue 3中集成这个框架呢答案就是我们自己实现与ECharts对应的Vue组件即可。
![图片](https://static001.geekbang.org/resource/image/4b/8c/4b0df7c9e10023fc216530c47c013d8c.png?wh=1662x868)
在Vue 3中集成ECharts的最简单的方式就是封装一个Chart组件把上面代码中的option配置以参数的形式传递给Chart组件然后组件内部进行渲染即可。
我们还是结合代码直观体验一下。在下面的代码中template设置了一个普通的div作为容器通过mount和onUnmounted生命周期内部去初始化图表实现ECharts框架中图表的渲染和清理然后initChart内部使用echart的API进行渲染这样就实现了图表的渲染。
```html
<template>
<div ref="chartRef" class="chart"></div>
</template>
<script setup>
import * as echarts from 'echarts'
import {ref,onMounted,onUnmounted} from 'vue'
// 通过ref获得DOM
let chartRef = ref()
let myChart
onUnmounted(()=>{
myChart.dispose()
myChart = null
})
onMounted(()=>{
myChart = echarts.init(chartRef.value)
const option = {
tooltip: {
trigger: 'item'
},
color: ['#ffd666', '#ffa39e', '#409EFF'],
// 饼图数据配置
series: [
{
name: '前端课程',
type: 'pie',
radius: '70%',
data: [
{value: 43340, name: '重学前端'},
{value: 7003, name: 'Javascript核心原理解析'},
{value: 4314, name: '玩转Vue3全家桶'}
]
}
]
}
myChart.setOption(option)
})
</script>
```
在上面,我们虽然实现了可视化组件的封装,但因为逻辑并不复杂,所以我们的实现还比较简略。
我们当然可以尝试去实现一下更详细的可视化组件封装但因为ECharts是一个非常复杂的可视化框架有饼图地图等不同的图表类型如果引入ECharts全部代码的话项目的体积会变得非常臃肿。所以如果我们能按照不同的图表类型按需引入ECharts那么除了能够让组件使用起来更方便之外整体项目的包的大小也会优化很多。
## 指令的封装
接下来,我们再介绍一下指令增强型组件的封装。
比如我们常见的图片懒加载的需求这一需求的实现方式就是在img的标签之上再加上一个v-lazy的属性。而图片懒加载和指令增强型组件的封装的关系在于v-lazy指令的使用方式是在HTML标签上新增一个属性。Vue内置的指令我们已经很熟悉了包括v-if、v-model等等。像图片懒加载这种库和DOM绑定但是又没有单独的组件渲染逻辑的情况通常在Vue中以指令的形式存在。
在Vue中注册指令和组件略有不同下面的代码中我们注册实现了v-focus指令然后在input标签中加上v-focus指令在指令加载完毕后鼠标会自动聚焦到输入框上这个实现在登录注册窗口中很常见。
```javascript
// 注册一个全局自定义指令 `v-focus`
app.directive('focus', {
// 当被绑定的元素挂载到 DOM 中时……
mounted(el) {
// 聚焦元素
el.focus()
}
})
```
指令的生命周期和组件类似首先我们要让指令能够支持Vue的插件机制所以我们需要在install函数内注册lazy指令。这种实现Vue插件的方式在vuex和vue-router两讲中已经带你学习过了这里的代码里我们使用install方法在install方法的内部去注册lazy指令并且实现了mounted、updated、unmounted三个钩子函数。
```javascript
const lazyPlugin = {
install (app, options) {
app.directive('lazy', {
mounted: ...,
updated: ...,
unmounted: ...
})
}
}
```
我们通过lazy指令获取到当前图片的标签并且计算图片的位置信息判断图片是否在首页显示。如果不在首页的话图片就加载一个默认的占位符就可以了并且在页面发生变化的时候重新进行计算这样就实现了页面图片的懒加载。
与懒加载类似的还有我们组件库中常用的v-loading指令它用来显示组件内部的加载状态我们在Element3中。也有类似的指令效果下面的代码中我们注册了loadingDirective指令并且注册了mounted、updated、unmounted三个钩子函数通过v-loading的值来对显示效果进行切换实现了组件内部的loading状态。
动态切换的Loading组件能够显示一个circle的div标签通过v-loading指令的注册在后续表格、表单等组件的提交状态中加载状态就可以很方便地使用v-loading来实现。
```javascript
const loadingDirective = {
mounted: function (el, binding, vnode) {
const mask = createComponent(Loading, {
...options,
onAfterLeave() {
el.domVisible = false
const target =
binding.modifiers.fullscreen || binding.modifiers.body
? document.body
: el
removeClass(target, 'el-loading-parent--relative')
removeClass(target, 'el-loading-parent--hidden')
}
})
el.options = options
el.instance = mask.proxy
el.mask = mask.proxy.$el
el.maskStyle = {}
binding.value && toggleLoading(el, binding)
},
updated: function (el, binding) {
el.instance.setText(el.getAttribute('element-loading-text'))
if (binding.oldValue !== binding.value) {
toggleLoading(el, binding)
}
},
unmounted: function () {
el.instance && el.instance.close()
}
}
export default {
install(app) {
// if (Vue.prototype.$isServer) return
app.directive('loading', loadingDirective)
}
}
```
## 引入第三方库的注意事项
我们封装第三方库的目的是实现第三方框架和Vue框架的融合提高开发效率。这里我跟你聊几个和引入第三方库相关的注意事项。
首先无论是引用第三方库还是你自己封装的底层库在使用它们之初就要考虑到项目的长期可维护性其次尽可能不要因为排期等问题一股脑地把第三方库堆在一起虽然这样做可以让项目在早期研发进度上走得很快但这样会导致项目中后期的维护成本远远大于重写一遍代码xxx的成本。
然后是Vue中的mixinextends机制能不用就不用这两个API算是从Vue 2时代继承下来的产物都是扩展和丰富Vue 2中this关键字在项目复杂了之后mixin和extends隐式添加的API无从溯源一旦多个mixin有了命名冲突调试起来难度倍增。
项目中的全局属性也尽可能少用全局变量是最原始的共享数据的方法Vue 3中我们使用app.config.globalProperties.x注册全局变量要少用它的主要原因也是项目中的全局变量会极大的提高维护成本。有些监控场景必须要用到就要把所有注册的全局变量放在一个独立的文件去管理。
最后我们引入第三方框架和库的时候一定要注意按需使用比如我们只用到了ECharts中的某几种类型的图也只用到了Element3中的部分组件。现在引入全部代码的方式会让项目体积越来越大关于代码体积优化的内容我们在18讲谈性能优化时也会详细介绍。
## 总结
今天的这一讲的内容就学完了我们来复习一下今天学到的知识。首先我们介绍了Vue中如何封装第三方工具框架比如axiosNProgress等这些框架和Vue耦合性不强直接引入使用即可。然后我讲到了Vue中封装可视化组件库的方式也就是把第三方库放在Vue的组件内部执行。
就像对于ECharts、wangEditor等成熟的框架来说对这些框架进行Vue 3框架的适配工作主要适配的载体就是组件。你可以选择直接透传所有option配置来做一个很浅的封装也可以针对需要用的组件类型逐个封装比如ECharts可以封装PieBar等不同类型的组件。
之后我们讲解了指令增强型组件的封装这种库和DOM绑定但是又没有单独的组件渲染逻辑通常在Vue中以指令的形式存在比较常见的就是图片懒加载指令以及loading指令我们项目中也会用到这两个指令来增强组件。
最后,我也给你介绍了一些引入第三方库时,需要你注意的事项,例如**从项目开始之初就要考虑到长期维护的成本不要一股脑地堆砌代码要学会全面使用Composition API 组织代码、少用全局变量,以及不要引入第三方库全部代码,这些都是很值得你注意的地方**。
## 思考题
最后留一个思考题,你的项目中还有什么第三方框架需要引入呢?大家可以在评论区分享你的答案,也欢迎你把这一讲的内容分享给你的同事、朋友们。