vue项目中,窗口大小不变(排除window监听resize),侧边菜单栏折叠展开,导致右边内容区域宽度大小变化,echarts图表的宽度超出或者小于操作后的 原图表容器区域的宽度;
常规解决办法的是监听窗口的变化window.addEventListener(“resize”),但当前bug是窗口不变,内部元素的宽度变化,所有window监听不生效。
methods:{
//调用echarts的resize()
onResize(){
this.charts.messagePie && this.charts.messagePie.resize();
this.charts.onLineChart && this.charts.onLineChart.resize();
this.charts.activeUserLine && this.charts.activeUserLine.resize();
}
}
1.是否可以类似监听窗口的resize一样来监听元素,发现元素没有这个resize;
2.监听侧边栏折叠的状态来调用抽取的onResize()方法,发现不生效;
watch:{
//监听菜单栏折叠
collapsed() {
this.onResize();
},
}
3.网上查了资料说是可以使用MutationObserver来监听侧边栏元素的属性变化,测试发现仍然不可行,此时过渡动画没有完成(第4点),加个setTimeout(onResize(),200)即可;
我查到的:MutationObserver不能监听css变化,这里只能监听内联属性style变化。(如果有误,请告知,谢谢!)
let MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
let element = document.querySelector('.ant-layout-sider');//侧边栏元素
this.observer = new MutationObserver(()=>{
setTimeout(()=>{this.onResize()},200)
});
this.observer.observe(element, {
attributes: true,
attributeFilter: ['style'],
attributeOldValue: true,
});
4.无意间发现侧边栏操作时有个transition:all 0.2s;过渡属性,是不是可以过渡完再执行? 发现可行,但是设置定时器0.2s着实有点不可取,继续查资料;
//监听菜单栏折叠,过渡动作结束后执行
collapsed(nVal) {
//侧边栏折叠时有0.2s过渡动画执行时间,过渡动画结束后再执行onResize
setTimeout(() => {
this.onResize();
}, 200);
},
5.根据第4点,可以监听元素过渡完 transitionend / webkitTransitionEnd,但是会触发多次因为过渡css属性有多个;
let _sider = document.querySelector('.app-sider');
_sider.addEventListener('transitionend',this.onResize,false);
可以通过触发元素是否为监听元素的width和防抖策略来过滤,然后在beforeDestory生命周期时取消监听;
removeEventListener在移除监听时,回调函数必须使用外部函数,类似下面的this.siderTransitionendListener,而不能是function(){ this.siderTransitionendListener },否则无法移除监听;
mounted(){
let _sider = document.querySelector('.app-sider'); //侧边栏
_sider.addEventListener('transitionend',this.siderTransitionendListener,false);
this.$once('hook:beforeDestroy', () => {
_sider.removeEventListener('transitionend', this.siderTransitionendListener, false);
});
},
methods:{
//侧边栏width过渡监听
siderTransitionendListener(e) {
let _sider = document.querySelector('.app-sider');
if (e.target == _sider && e.propertyName == 'width') {
// 防止transitionend 多次触发执行
commonUtil.debounce(this.onResize, 300)();
}
},
}
debounce(fn, wait = 200, _timer = null) {
let timer = _timer;
return function() {
let args = arguments;
if (timer) {
clearTimeout(timer);
timer = null;
}
timer = setTimeout(() => {
fn.apply(this, args);
}, wait);
};
}
mounted(){
window.addEventListener('resize', this.windowResizeListener, false);
this.$once('hook:beforeDestroy', () => {
window.removeEventListener('resize', this.windowResizeListener, false);
});
},
methods: {
//窗口resize监听,不用windowResizeListener: commonUtil.debounce(this.onResize, 300) 此时this为undefined
windowResizeListener: commonUtil.debounce(function () {
this.onResize();
}, 300),
}
mounted(){
window.onresize = commonUtil.debounce(this.onResize, 300);
this.$once('hook:beforeDestroy', () => {
window.onresize = null;
});
}