什么?css 把浏览器搞崩了~
发布于 3 年前 作者 MeetTheBest 4435 次浏览 来自 问答

背景

使用 vue + element UI 进行组件(Tabs)操作,重写了部分的 tabs 组件的样式

复现地址

https://codepen.io/meetthebest/pen/jOyMQLV

复现操作

点击页面的 add tab 按钮,预计点击6次左右,页面将卡死

有大佬知道是什么问题导致的吗 ? 个人排查过程中,发现如下图中的 width 属性注释或者删除了,就不会卡死🤔

image.png

目前还没找到问题,希望知道的大佬指导一下,感谢!!!

13 回复

神奇,看js也没卡死,如果楼主解决了记得@我下

感觉上不是 js 死循环了,而是绘制 dom 的时候卡住了,比如卡住的时候在控制台执行 document.body.append('<b>Hello world!</b>') 是没反应的,但是敲 console.log('hello') 是可以的 我猜测你的加 tab 逻辑里是不是会不停触发 dom 的重绘,导致页面卡住

vue里面的代码一直在递归调用,看起来像是框架的bug。

先把控制台切换到CodePen(jOyMQLV) 等卡住的时候按下 F8 暂停js,然后随便抛一个什么东西出来,就可以在控制台看到一个超长的调用堆栈。 image.png

throw 123
VM75:1 Uncaught 123
eval @ VM75:1
flushSchedulerQueue @ vue.js:4300
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915
Promise.then (async)
timerFunc @ vue.js:1942
nextTick @ vue.js:1999
queueWatcher @ vue.js:4403
update @ vue.js:4543
notify @ vue.js:745
reactiveSetter @ vue.js:1070
proxySetter @ vue.js:4630
update @ index.js:1
updated @ index.js:1
invokeWithErrorHandling @ vue.js:1863
callHook @ vue.js:4220
callUpdatedHooks @ vue.js:4352
flushSchedulerQueue @ vue.js:4337
(anonymous) @ vue.js:1989
flushCallbacks @ vue.js:1915

把 important 的优先取消掉,提级操作过多其实很耗计算的。

以为是标题党

@yuanliwei 其实还没不是太明白,为何会引起 Vue 的内部递归,可是如果注释了那 width 属性,又为啥可以了

这样就下出css的结论?明显就是js问题嘛,肯定是哪段逻辑和宽度有关没处理对或者就没考虑你这种情况

@linlifengx 老哥,demo 是从饿了么那么直接拿来的(饿了么: https://codepen.io/pen/ ),你可以把前面有问题的地址的css 复制进行,就能重现。

至于具体啥问题,这个确实我没有头绪😞~ 只能望各位大佬解惑。

image.png

问题原因:width: 100%!important; 放在了 .is-scrollable下面,element-ui会在tab中的内容宽度超出自身宽度的时候动态添加.is-scrollable,因此出现死循环、

具体流程如下:

tab中内容宽度超出自身宽度 element-uitab添加了一个.is-scrollable 此时width: 100%!important;起作用了,tab内容的宽度被设置为tab的宽度 然后element-ui.is-scrollable移除 tab中内容宽度超出自身宽度 element-uitab添加了一个.is-scrollable 此时width: 100%!important;起作用了,tab内容的宽度被设置为tab的宽度 然后element-ui.is-scrollable移除 tab中内容宽度超出自身宽度 element-uitab添加了一个.is-scrollable 此时width: 100%!important;起作用了,tab内容的宽度被设置为tab的宽度 然后element-ui.is-scrollable移除 tab中内容宽度超出自身宽度 element-uitab添加了一个.is-scrollable 此时width: 100%!important;起作用了,tab内容的宽度被设置为tab的宽度 然后element-ui.is-scrollable移除 tab中内容宽度超出自身宽度 …

@yuanliwei 盲猜也是element-ui动态调整css陷入死循环了,不过没找到对应代码

代码从调用堆栈点过去就是了 image.png image.png image.png

@yuanliwei 看样子应该是加了 width 和框架内部发生了 死循环了。 感谢大佬解惑哈👍

mark,学习了!

回到顶部