希望大家应该也遇到过,当我们使用echarts时,在侧边导航折叠展开时,resize方法不生效的问题。以下提供两种个人比较推荐的解决方法。
方法一
使用 setTimeout
可以看到elementui的过渡时间是0.3s

所以在监听侧边栏折叠的时间使用settimeout,0.3s后执行resize方法。
| watch(() => hasCollapse.value, (val) => { |
| setTimeout(() => { |
| chart.value?.resize(); |
| }, 300); |
| }) |
复制
方法二(推荐)
编写动画函数执行resize方法
| |
| export const useAnimation = ( |
| duration: number, |
| from: number, |
| to: number, |
| callback: (value: number) => void |
| ) => { |
| const startTime = Date.now(); |
| const diff: number = to - from; |
| const average: number = diff / duration; |
| let value: number = from; |
| callback(value); |
| const _animate = () => { |
| const currentTime: number = Date.now(); |
| const timeDiff: number = currentTime - startTime; |
| if (timeDiff >= duration) { |
| value = to; |
| callback(value); |
| return; |
| } |
| value = diff < 0 ? from + (timeDiff * average) : timeDiff * average; |
| callback(value); |
| requestAnimationFrame(_animate); |
| } |
| _animate(); |
| } |
复制
注意:需要结合自定义hook,可以封装一个hook,返回容器的宽(window.innerWidth - 侧边导航菜单的宽度),这里我侧边菜单的宽度是 200(展开状态)和 60(折叠状态)
| |
| import { computed, ref, watch } from "vue"; |
| import { useSettingStore } from "@/store"; |
| import { useEventListener } from "./event"; |
| const settingStore = useSettingStore(); |
| |
| export const useWidthHeight = () => { |
| const hasCollapse = computed<boolean>(() => { |
| return settingStore.hasCollapse; |
| }) |
| |
| const mainHeight = ref<number>(window.innerHeight - 60); |
| |
| const mainWidth = ref<number>(window.innerWidth - (hasCollapse.value ? 60 : 200)); |
| const updateWidthHeight = () => { |
| mainHeight.value = window.innerHeight - 60; |
| mainWidth.value = window.innerWidth - (hasCollapse.value ? 60 : 200); |
| } |
| |
| useEventListener(window, 'resize', updateWidthHeight); |
| |
| watch(hasCollapse, (val) => { |
| updateWidthHeight(); |
| }) |
| return { height: mainHeight, width: mainWidth }; |
| } |
复制
当监听到折叠时这个主体宽度是会变化的。
在组件中导入这两个方法
| import { useAnimation } from '@/utils/animation'; |
| import { useWidthHeight } from '@/hooks'; |
| const { width } = useWidthHeight(); |
| const onResize = () => { |
| chart.value?.resize(); |
| } |
| onMounted(() => { |
| initChart(); |
| window.addEventListener('resize', onResize); |
| }) |
| onBeforeUnmount(() => { |
| window.removeEventListener('resize', onResize); |
| }) |
| |
| watch(width, (nVal, oVal) => { |
| |
| useAnimation(300, nVal, oVal, () => { |
| chart.value?.resize(); |
| }) |
| }) |
复制
效果不会像使用setTimeout方法,在最后突然抖动一下去resize,这个方法可以在过渡中resize,体验相对友好。
当然useAnimation这个工具函数用途不止如此,还可以做一些其他动画过渡效果,大家可以试一试,希望对你们有用。
方法三(推荐)
使用 ResizeObserver 封装 v-resize 指令
| const map = new WeakMap(); |
| const resizeOb = new ResizeObserver((entries) => { |
| for (const entry of entries) { |
| const handler = map.get(entry.target); |
| let width, height; |
| if (entry.borderBoxSize) { |
| const contentBoxSize = Array.isArray(entry.borderBoxSize) |
| ? entry.borderBoxSize[0] |
| : entry.borderBoxSize; |
| width = contentBoxSize.inlineSize; |
| height = contentBoxSize.blockSize; |
| } else { |
| width = entry.contentRect.width; |
| height = entry.contentRect.height; |
| } |
| handler({ width, height }); |
| } |
| }); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| const vResizeEl = { |
| mounted(el, binding) { |
| const value = binding.value; |
| if (value && typeof value === 'function') { |
| map.set(el, value); |
| } else { |
| throw new Error('binding value is not a function'); |
| } |
| resizeOb.observe(el); |
| }, |
| unmounted(el) { |
| resizeOb.unobserve(el); |
| }, |
| }; |
| |
| export default vResizeEl; |
| |
复制
用法
| <div ref="chartInstance" v-resize="handleResize"> </div> |
复制
| |
| const handleResize = () => { |
| if (chartInstance.value) { |
| chartInstance.value.resize(); |
| } |
| }; |
复制