图片 3

JS奇技之利用scroll来监听resize详解_javascript技巧_脚本之家

前言

固钉组件的作用是将页面元素固定在可视区域之内。

大家都知道知道原生的 resize 事件只能作用于 defaultView 即 window
上,那么我们应该通过什么样的方式来监听其他元素的大小改变呢?笔者最近学习发现了一种神奇的方法,通过
scroll 事件来间接实现 resize
事件的监听,本文将对这种方式进行原理的剖析与代码实现。

图片 1

原理

恩!是这样

首先,我们先来看一下 scroll 事件是干嘛的。

需求

固钉的基本功能就是将元素固定在页面的特定位置,即使存在滚动条的情况下,固钉元素仍然可以固定在设定的位置。

这里位置固定所指的参考有两种情况:

  1. 元素相对窗口固定位置。
  2. 元素相对于父容器固定位置。

常规情况下,我们使用的是元素相对于窗口位置固定,这里直接使用fixed布局就可以了,但是对于第二种需求就不容易实现了,这也是固钉组件主要实现的功能。

The scroll event is fired when the document view or an element has been
scrolled.

预备知识

当文档视图或者元素滚动的时候会触发 scroll 事件。

pageYOffset pageXOffset

pageYOffset
pageXOffset是window的属性,表示整个页面滚动过的值,可以使用body元素的scrollTop属性替代。

也就是说元素滚动的时候会触发这个事件,那么什么时候元素会滚动?当元素大于其父级元素,且父级元素允许其滚动的时候,该元素可以进行滚动。换句话说,元素可以滚动意味着父子元素大小不一致,这是这个方法的核心。

scrollTop scrollLeft

scrollTop scrollLeft是Element的属性,表示一个具有属性的元素滚动过的值。

那么我们需要让元素大小发生改变时,使得 scrollLeft 或者 scrollTop
发生改变,从而触发 scroll 事件,进一步得知其大小发生了改变。

offsetTop offsetLeft

要想解释offsetTop 以及 offsetLeft的值,需要理解offsetParent的概念。
offsetParent可以返回距离当前元素最近的采用定位(position属性值为fixed、relative或者absolute)祖先元素。
如果祖先元素中没有采用定位的元素,则返回body对象。
offsetTop/offsetLeft返回值表示当前元素上边缘/左边缘距离offsetParent返回元素的距离的数值,单位是像素。

总结:scroll是与滚动相关的属性,offset是与offsetParent相关的属性值

监听元素变大

innerHeight

innerHeight为window的属性,指窗口的大小(不包含工具条与滚动条)。

元素变大的时候,我们可以看到更多,其内部可滚动区域将慢慢减小,但这并不会造成滚动条位置的改变,但当元素大到让滚动条消失的时候会让
scrollLeft 或者 scrollTop 变成
0,这样我们就知道了元素变大了,因此我们其实只需要 1px
来判断,其图示如下:

clientHeight

clientHeight这个属性是只读属性,对于没有定义CSS或者内联布局盒子的元素为0,同时它是元素内部的高度(单位像素),包含内边距,但不包括水平滚动条、边框和外边距。
clientHeight 可以通过 CSS height + CSS padding – 水平滚动条高度.

监听元素变小

offsetHeight

在IE6,IE7,IE8以及最新的的FF, Chrome中,在元素上都是offsetHeight =
clientHeight + 滚动条 + 边框。

当元素变小的时候,可滚动区域会变大,滚动条的位置其实并不会进行改变,这里采取的做法是,让可滚动区域和父元素成一定的比例一起缩小,让父元素来挤压滚动区域,从而间接改变滚动条
scrollLeft 或者 scrollTop 的大小,文字描述可能不是很清楚,我们看下图:

scrollHeight

这个高度与滚动条无关,是内容的实际高度。

计算方式 :scrollHeight = topPadding + bottomPadding + 内容margix
box的高度。

总结:clientHeight与scrollHeight与滚动条有关,前者与设置的height有关,后者与元素所占据的实际高度有关

通过以上两种方式,我们可以就可以获得 resize 事件。

fixed布局

fixed布局是我们通常采用的实现元素固定在窗口的特定位置,如下图所示:

图片 2

image

但是如果我们想实现基于任意父容器的固钉呢?即使其固定在父容器的指定位置,而不是单纯的固定在窗口的指定位置,如下图所示:

图片 3

fixedToContainer.gif

实现

实现原理

其实实现第二种需求的固钉仍然是基于fixed布局的,只不过我们这里加入的事件监听,动态的设置元素的top/bottom等值,以在视觉效果上实现相对于父元素的位置固定。