先说下我遇到的情况,项目就是很经典的后台管理系统,菜单在左侧,并且可以收缩,首页是个可视化页面,用到了dataV边框组件,但是收缩菜单的时候问题出现了,边框无法自适应父容器,下面是效果图:
可以很明显的看出来,当我们收缩菜单的时候,中间的dataV边框并没有自适应容器,展开的时候又超出了容器的宽度,所以bug就来了,为了解决百度找了好多资料,但基本上都是说使用组件内部的initWH方法重置组件的宽高,官网也确实有说
但我加上就是不起作用!!
干脆就直接找源码看下了,看能不能找到答案,这个边框组件其实是:最外层有个容器,然后里面svg画出来的线,然后还有跟svg同级一个div作为插槽,就是我们在边框组件内部写的内容,然后js代码部分确实有个initWH方法,先贴下源码:
可以看到initWH方法中的 this.width 和 this.height 就是我们的svg对应的宽高,也就是我们没有自适应的宽高!然后就试着在initWH中打印看下这个 this.width 和 this.height 和 dom,从initWH方法中可以看出这个width和height其实 就是我们的父容器的宽高,打印出来之后发现dom的宽度(最外层的div就是类名位dv-border-box-8)已经变了,但是把dom.clientWidth和dom.clientHeight赋值给我们的this.width和this.height(就是我们的svg的宽高),发现赋上去的值还是改变之前的值!!这就奇怪了,后来换个思路,想了一下菜单展开收缩的时候是不是有一定的时间,但是多少时间我们控制不了,也不确定,所以是不是还没收缩展开完成我们就去拿dom元素的宽高赋值了,所以我在这加了个setTimeout 延迟5000再赋值:
initWH (resize = true) {
console.log('触发 initWH----->>>')
const { $nextTick, $refs, ref, onResize } = this
return new Promise(resolve => {
$nextTick(_ => {
const dom = this.dom = $refs[ref]
setTimeout(() => {
this.width = dom ? dom.clientWidth : 0
this.height = dom ? dom.clientHeight : 0
}, 5000)
if (!dom) {
console.warn('DataV: Failed to get dom node, component rendering may be abnormal!')
} else if (!this.width || !this.height) {
console.warn('DataV: Component width or height is 0px, rendering abnormality may occur!')
}
if (typeof onResize === 'function' && resize) onResize()
resolve()
})
})
},
发现确实是可以自适应!这基本就可以确认原因了,就是我们菜单收缩的时候,是有一定时间的,我们要等到菜单收缩完成之后再拿dom元素赋值给我们的svg宽高,经过测试我们把延迟写到300毫秒就可以了。
最终结论就是:
如果是一般情况下,我们都不需要调用initWH方法,默认宽高也是100% * 100%,并且监听了window的resize方法,重置宽高。
特殊情况下,可以选择调用initWH方法重置宽高,但是一定是得等dom元素更新完成之后再去调用,要不然拿到的宽度也不是最终变化完的宽高,导致不能自适应,就像我这个例子,菜单展开收缩的时候,我们要延迟一会儿再去调用initWH就可以了
我这个例子最终的解决方案就是,监听菜单展开收缩的变化,当改变的时候延迟3秒调用initWH方法就可以了!
<template>
<div class="home">
<div class="lt">
<div class="branch"></div>
<div class="branch"></div>
<div class="branch"></div>
</div>
<div class="cen">
<div class="cen-top">
<dv-border-box-8 ref="borderBox"> </dv-border-box-8>
</div>
<div class="cen-bot"></div>
</div>
<div class="rt">
<div class="branch"></div>
<div class="branch"></div>
<div class="branch"></div>
</div>
</div>
</template>
<script>
export default {
computed: {
isCollapse() {
return this.$store.state.common.isCollapse;
}
},
watch: {
isCollapse() {
setTimeout(() => {
this.$refs.borderBox.initWH()
}, 300)
}
}
}
</script>
最终效果图: