背景
根据多次开发可视化大屏的经验,两个常规的需求就是每个图表根据窗口的大小自适应展示和图表的排版要求,vfullscreen插件就是为解决这两个需求而存在。
vfullscreen插件其实已经发布三年多了,当初有太多的大屏开发需求,为了快速开发,就尝试封装了这个插件。而升级的动力是源于Vue2.x的版本于2023年12月31号就停止维护了,拖了这么久终于在昨晚publish到npm库上,在这里也算是记录下升级路程。
对比
对两个需求的分析,大概实现的内容:
- 要获取设计图上图表大小。监听窗口大小的变动,实时修改图表大小
- 需要两个指定的排版组件
因此需要至少4个组件来完成:
- vFullscreen: 根组件,完成模块相对于窗口大小的计算和进入/退出全屏功能
- vCol:flex的column布局组件,包含一个slot标签
- vRow:flex的row布局组件,包含一个slot标签
- vChart: 包裹大屏所有图表的基础组件,包含一个slot标签
基于vue2的开发思路:
- 应对第一个需求:借鉴了vue1.x的事件订阅发布流程。维护了一个拥有dispatch方法和broadcast方法的emitter对象,使用
mixin的方式供各个组件使用。 - 第二个需求就相对简单了:组件的排版功能借助css的flex布局就可以实现了
之所以使用事件订阅发布的模式,是因为作为一个功能简单的插件,1,代码量不会太大;2,组件嵌套使用时,事件的触发是要跨层级的,vue2.x提供的$emit方法使用起来的就会太过复杂。
dispatch和broadcast方法利用vue2.x提供的组件实例中的
$parent和$children对象向上或向下查找组件,并调用组件中的方法;
代码github地址: github.com/LeeZ-2017/v…
插件的npm地址:vfullscreen - npm (npmjs.com)
基于vue3的开发思路:
vue3.x弃用了$children,官方建议使用$ref获取子组件实例,而嵌套组件是通过slot形式插入,且当嵌套组件数量过多时,不可能专门为每一个嵌套组件都添加ref;而ref获取的slot组件也需要再次构造才能拿到实例。所以采用的了嵌套组件内监听具有响应性的provide/inject注入的width和height,达到修改组件大小的目的。
所以最终的开发思路是:
- 嵌套组件使用dispatch方法向上提供组件的原始大小;监听
inject注入的计算后的大小 - 组件的排版功能依然借助css的flex布局实现
代码已提交到gitee: gitee.com/liz42/vfull…
插件已提交到npm:vfullscreen - npm (npmjs.com)
欢迎提出更多意见。
打包
本项目采用的版本如下:
- Node: 16.13.0
- Vue: 3.4.14
- Vite: 5.0.10
vite打包有专门的库模式,但是打包后的文件中包含css文件时,需要vite-plugin-libcss插件把css文件引入到js文件中;
配置vite的rollupOptions字段,可以把项目依赖的vue代码排除在插件包之外,减少包体积;
在使用npm发布包时,pubilsh默认会上传:dist/package/README文件或文件夹。
vue3.x相比vue2.x在插件开发方面也有一定的区别:vue3需要给每一个组件添加install方法,且打包入口需要再次实现install方法,并导出该方法。
vue3的方式:
/** 插件入口--index.js **/
import vfullscreen from './index.vue'
import vCol from './widget/column.vue'
import vRow from './widget/row.vue'
import vChart from './widget/chart.vue'
const components = [
vfullscreen,
vRow,
vCol,
vChart
]
components.forEach(component => {
component.install = function(Vue, opts = {}) {
Vue.component(component.name, component);
}
})
export default components
打包入口js文件:
import components from './components/index.js'
import vfullscreen from './components/index.vue'
import vCol from './components/widget/column.vue'
import vRow from './components/widget/row.vue'
import vChart from './components/widget/chart.vue'
const install = function(Vue, opts = {}) {
components.forEach(component => {
Vue.component(component.name, component);
});
};
export {
vfullscreen,
vCol,
vRow,
vChart,
install
}
vue2的方式:
/** 打包入口--js **/
import vfullscreen from './components'
import vCol from './components/widget/column'
import vHead from './components/widget/head'
import vFoot from './components/widget/foot'
import vRow from './components/widget/row'
import vChart from './components/widget/chart'
const components = [
vfullscreen,
vHead,
vRow,
vCol,
vChart,
vFoot
]
const install = function(Vue, opts = {}) {
components.forEach(component => {
Vue.component(component.name, component);
});
};
if (typeof window !== 'undefined' && window.Vue) {
install(window.Vue);
}
export default {
vfullscreen,
vHead,
vRow,
vCol,
vChart,
vFoot
}
总结
升级之初,本以为是一次简单的vue2.x 到vue3.x项目更新,而且vue3.x本身依然支持option Api模式,所以觉得升级会比较快一点。然而,只能说理想很丰满,现实很骨感。这也重新认识了vue3更多的特性。