Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CSS黑魔法] 感知DOM resize的骚操作 #12

Open
renjie1996 opened this issue Aug 10, 2018 · 1 comment
Open

[CSS黑魔法] 感知DOM resize的骚操作 #12

renjie1996 opened this issue Aug 10, 2018 · 1 comment

Comments

@renjie1996
Copy link
Owner

renjie1996 commented Aug 10, 2018

CSS黑魔法 - 感知DOM resize的骚操作

image
https://jsfiddle.net/xurenjie/fahbes8q/1/

tip:你可以使用控制台手动修改左边的方块的css,发现右边的也跟着变化,说明绑上了resize的钩子

什么叫感知DOM的resize,简单来说就是找到一个钩子,当DOM的大小尺寸发生改变时,我能够有钩子触动事件。resize事件只能绑在document元素,而jq的resize更像是我们没做socket的轮询方案,有没有一种方式是自动感知的,类似下面这个例子,你可以开启浏览器的debugger窗口改变css,从而触发resize事件,而不是使用拖动这个钩子去触发。

resize事件?

很遗憾resize事件只支持document元素的resize

https://developer.mozilla.org/en-US/docs/Web/Events/resize
image

ResizeObserver ?

兼容性让你没想法
image

jquery resize?

https://github.com/cowboy/jquery-resize/blob/master/jquery.ba-resize.js
这个思路其实挺常见的,在前端日志滚动到最底部时,经常可以去轮询,在轮询中改变滚动位置,思路就是轮询,源码见下
image
这样的做法是及其消耗性能的

DOM resize的最佳实践

在阅读ElementUi和iview源码时发现这个黑魔法实现思路
resize-observer-polyfill实现思路大致如下:

事件fake

这个方法是在被监听元素里包裹一个跟元素位置大小相同的隐藏块。隐藏块可以滚动,并有一个远远大于它的子元素。当被监测元素尺寸变化时期望能触发隐藏块的滚动事件。这个方法最麻烦的是触发滚动事件的条件。

可以参考ScrollingElement Polyfill的规范文档https://github.com/mathiasbynens/document.scrollingElement/blob/master/scrollingelement.js
w3c规范

Whenever an element gets scrolled (whether in response to user interaction or by an API)
问题关键,位置相同的时候,滚动事件不会发生。

image

重排

根据前面的整体思路,当被监测元素尺寸发生变化时,隐藏元素也跟着变化。于是引发了 Layout/Reflow 使到重新计算滚动位置 position。[http://jsfiddle.net/xurenjie/mzp2h9ax/](http://jsfiddle.net/xurenjie/mzp2h9ax/)
但这时也许你会发现 position 根本没有变化,如图一。

这是因为应上面的 2.1 和 3.1 公式。每次计算滚动距离都会跟可滚动的空间比较取最小值。
初始的 1 个事件就是上面提到的 event loop 导致的。
可以观察滚动发生,我们期望容器达到最大时 x 和 y 都没有达到最小值,所以子元素的大小须比容器最大值要大。
动图同时也可观察到容器变小时没反应。按上面的公式也很容易知道,容器变小了,差值变大了,所以最小值还是 x 和 y,故不触发滚动。

再看回公式,我们希望容器变小时,差值也变小。那么只能是让 scrolling area 也跟着变小了。如果子元素大小改为百分比行不?我们来证明一下。

设容器宽度为 x1 或者 x2,其中 x2 > x1,子元素大小为 n * x1 或 n * x2,因我们不设 padding,则有

n * x1 - x1 < n * x2 - x2
↓
(n - 1) * x1 < (n - 1) * x2
↓
n > 1

证明了通过百分比是可行的。

同时我们期望容器达到最小时 x 和 y 都没有达到最小值,容器为 0 时无意义,故设最小为 1,则

(n - 1) * 1 >= 1
↓
n >= 2

故我们只需让子元素大小至少为 200% 就可以

@adamma1024
Copy link

这方法有点秀啊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants